2013-11-27 00:38:30 +00:00
/*
2007-03-29 22:34:40 +00:00
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
2014-02-05 21:02:28 +00:00
* Copyright ( C ) 2005 - 2014 , 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 ) :
2013-11-27 00:38:30 +00:00
*
2009-02-04 21:20:54 +00:00
* Anthony Minessale II < anthm @ freeswitch . org >
2007-03-29 22:34:40 +00:00
* Paul D . Tinsley < pdt at jackhammer . org >
* Neal Horman < neal at wanlink dot com >
* Matt Klein < mklein @ nmedia . net >
* Michael Jerris < mike @ jerris . com >
2011-04-20 17:09:03 +00:00
* Marc Olivier Chouinard < mochouinard @ moctel . com >
2007-03-29 22:34:40 +00:00
*
* switch_ivr_play_say . c - - IVR Library ( functions to play or say audio )
*
*/
2008-01-27 17:42:51 +00:00
2007-03-29 22:34:40 +00:00
# include <switch.h>
2010-03-03 20:49:38 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_phrase_macro_event ( switch_core_session_t * session , const char * macro_name , const char * data , switch_event_t * event , const char * lang ,
2007-03-30 00:15:25 +00:00
switch_input_args_t * args )
2007-03-29 22:34:40 +00:00
{
2008-01-23 20:59:25 +00:00
switch_event_t * hint_data ;
2011-04-20 17:09:03 +00:00
switch_xml_t cfg , xml = NULL , language = NULL , macros = NULL , phrases = NULL , macro , input , action ;
2007-03-29 22:34:40 +00:00
switch_status_t status = SWITCH_STATUS_GENERR ;
2007-11-01 11:28:26 +00:00
const char * old_sound_prefix = NULL , * sound_path = NULL , * tts_engine = NULL , * tts_voice = NULL ;
const char * module_name = NULL , * chan_lang = NULL ;
2008-01-28 07:26:10 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2014-04-09 04:48:09 +00:00
uint8_t done = 0 , searched = 0 ;
2007-11-07 23:37:22 +00:00
int matches = 0 ;
2008-09-09 18:24:13 +00:00
const char * pause_val ;
int pause = 100 ;
2011-04-20 17:09:03 +00:00
const char * group_macro_name = NULL ;
const char * local_macro_name = macro_name ;
switch_bool_t sound_prefix_enforced = switch_true ( switch_channel_get_variable ( channel , " sound_prefix_enforced " ) ) ;
switch_bool_t local_sound_prefix_enforced = SWITCH_FALSE ;
2007-03-29 22:34:40 +00:00
2012-12-10 16:56:07 +00:00
2007-03-29 22:34:40 +00:00
if ( ! macro_name ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " No phrase macro specified. \n " ) ;
2007-03-29 22:34:40 +00:00
return status ;
}
2012-12-10 16:56:07 +00:00
arg_recursion_check_start ( args ) ;
2007-03-29 22:34:40 +00:00
if ( ! lang ) {
chan_lang = switch_channel_get_variable ( channel , " default_language " ) ;
if ( ! chan_lang ) {
chan_lang = " en " ;
}
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " No language specified - Using [%s] \n " , chan_lang ) ;
2007-03-29 22:34:40 +00:00
} else {
chan_lang = lang ;
}
2008-10-02 17:10:05 +00:00
switch_event_create ( & hint_data , SWITCH_EVENT_REQUEST_PARAMS ) ;
2008-01-23 20:59:25 +00:00
switch_assert ( hint_data ) ;
2008-05-27 04:30:03 +00:00
2008-01-23 20:59:25 +00:00
switch_event_add_header_string ( hint_data , SWITCH_STACK_BOTTOM , " macro_name " , macro_name ) ;
switch_event_add_header_string ( hint_data , SWITCH_STACK_BOTTOM , " lang " , chan_lang ) ;
if ( data ) {
switch_event_add_header_string ( hint_data , SWITCH_STACK_BOTTOM , " data " , data ) ;
2010-03-03 20:49:38 +00:00
if ( event ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " data " , data ) ;
}
2008-01-28 21:07:20 +00:00
} else {
2008-05-27 04:30:03 +00:00
data = " " ;
}
2008-01-23 20:59:25 +00:00
switch_channel_event_set_data ( channel , hint_data ) ;
2007-03-29 22:34:40 +00:00
2011-04-20 17:09:03 +00:00
if ( switch_xml_locate_language ( & xml , & cfg , hint_data , & language , & phrases , & macros , chan_lang ) ! = SWITCH_STATUS_SUCCESS ) {
2007-03-29 22:34:40 +00:00
goto done ;
}
2011-04-20 17:09:03 +00:00
if ( ( module_name = switch_xml_attr ( language , " say-module " ) ) ) {
} else if ( ( module_name = switch_xml_attr ( language , " module " ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " Deprecated usage of module attribute. Use say-module instead \n " ) ;
} else {
module_name = chan_lang ;
2007-03-29 22:34:40 +00:00
}
2011-04-20 17:09:03 +00:00
if ( ! ( sound_path = ( char * ) switch_xml_attr ( language , " sound-prefix " ) ) ) {
if ( ! ( sound_path = ( char * ) switch_xml_attr ( language , " sound-path " ) ) ) {
sound_path = ( char * ) switch_xml_attr ( language , " sound_path " ) ;
2007-03-29 22:34:40 +00:00
}
2007-10-15 18:02:21 +00:00
}
if ( ! ( tts_engine = ( char * ) switch_xml_attr ( language , " tts-engine " ) ) ) {
2007-11-07 18:50:34 +00:00
tts_engine = ( char * ) switch_xml_attr ( language , " tts_engine " ) ;
2007-10-15 18:02:21 +00:00
}
2008-05-27 04:30:03 +00:00
2007-10-15 18:02:21 +00:00
if ( ! ( tts_voice = ( char * ) switch_xml_attr ( language , " tts-voice " ) ) ) {
2007-11-07 18:50:34 +00:00
tts_voice = ( char * ) switch_xml_attr ( language , " tts_voice " ) ;
2007-10-15 18:02:21 +00:00
}
2007-03-29 22:34:40 +00:00
2011-04-20 17:09:03 +00:00
/* If we use the new structure, check for a group name */
if ( language ! = macros ) {
2008-04-14 17:24:52 +00:00
char * p ;
2011-04-20 17:09:03 +00:00
char * macro_name_dup = switch_core_session_strdup ( session , macro_name ) ;
const char * group_sound_path ;
const char * sound_prefix_enforced_str ;
if ( ( p = strchr ( macro_name_dup , ' @ ' ) ) ) {
* p + + = ' \0 ' ;
local_macro_name = macro_name_dup ;
group_macro_name = p ;
if ( ! ( macros = switch_xml_find_child ( phrases , " macros " , " name " , group_macro_name ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Can't find macros group %s. \n " , group_macro_name ) ;
goto done ;
}
}
/* Support override of certain language attribute */
if ( ( group_sound_path = ( char * ) switch_xml_attr ( macros , " sound-prefix " ) ) | | ( group_sound_path = ( char * ) switch_xml_attr ( macros , " sound-path " ) ) | | ( group_sound_path = ( char * ) switch_xml_attr ( macros , " sound_path " ) ) ) {
sound_path = group_sound_path ;
}
2007-03-29 22:34:40 +00:00
2011-04-20 17:09:03 +00:00
if ( sound_prefix_enforced = = SWITCH_FALSE & & ( sound_prefix_enforced_str = switch_xml_attr ( macros , " sound-prefix-enforced " ) )
& & ( local_sound_prefix_enforced = switch_true ( sound_prefix_enforced_str ) ) = = SWITCH_TRUE ) {
switch_channel_set_variable ( channel , " sound_prefix_enforced " , sound_prefix_enforced_str ) ;
2007-03-29 22:34:40 +00:00
}
2011-04-20 17:09:03 +00:00
2007-03-29 22:34:40 +00:00
}
2011-04-20 17:09:03 +00:00
if ( ! ( macro = switch_xml_find_child ( macros , " macro " , " name " , local_macro_name ) ) ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Can't find macro %s. \n " , macro_name ) ;
2007-03-29 22:34:40 +00:00
goto done ;
}
2011-04-20 17:09:03 +00:00
if ( sound_path & & sound_prefix_enforced = = SWITCH_FALSE ) {
char * p ;
old_sound_prefix = switch_str_nil ( switch_channel_get_variable ( channel , " sound_prefix " ) ) ;
p = switch_core_session_strdup ( session , old_sound_prefix ) ;
old_sound_prefix = p ;
switch_channel_set_variable ( channel , " sound_prefix " , sound_path ) ;
}
2008-09-09 18:24:13 +00:00
if ( ( pause_val = switch_xml_attr ( macro , " pause " ) ) ) {
int tmp = atoi ( pause_val ) ;
if ( tmp > = 0 ) {
pause = tmp ;
}
}
2007-03-29 22:34:40 +00:00
if ( ! ( input = switch_xml_child ( macro , " input " ) ) ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Can't find any input tags. \n " ) ;
2007-03-29 22:34:40 +00:00
goto done ;
}
2009-02-10 19:09:06 +00:00
if ( switch_channel_pre_answer ( channel ) ! = SWITCH_STATUS_SUCCESS ) {
2009-03-16 18:49:58 +00:00
status = SWITCH_STATUS_FALSE ;
goto done ;
2009-02-10 19:09:06 +00:00
}
2007-03-29 22:34:40 +00:00
2014-04-09 07:40:18 +00:00
while ( input ) {
2010-03-03 20:49:38 +00:00
char * field = ( char * ) switch_xml_attr ( input , " field " ) ;
2007-03-29 22:34:40 +00:00
char * pattern = ( char * ) switch_xml_attr ( input , " pattern " ) ;
2008-05-16 18:40:39 +00:00
const char * do_break = switch_xml_attr_soft ( input , " break_on_match " ) ;
2010-03-03 20:49:38 +00:00
char * field_expanded = NULL ;
char * field_expanded_alloc = NULL ;
2014-04-09 07:23:48 +00:00
switch_regex_t * re = NULL ;
int proceed = 0 , ovector [ 100 ] ;
switch_xml_t match = NULL ;
2010-03-03 20:49:38 +00:00
2014-04-09 04:48:09 +00:00
searched = 1 ;
2010-03-03 20:49:38 +00:00
if ( ! field ) {
field = ( char * ) data ;
}
if ( event ) {
field_expanded_alloc = switch_event_expand_headers ( event , field ) ;
} else {
field_expanded_alloc = switch_channel_expand_variables ( channel , field ) ;
}
if ( field_expanded_alloc = = field ) {
field_expanded_alloc = NULL ;
field_expanded = field ;
} else {
field_expanded = field_expanded_alloc ;
}
2008-05-27 04:30:03 +00:00
2013-01-23 03:14:58 +00:00
if ( ! pattern ) {
pattern = " .* " ;
}
2014-04-09 07:23:48 +00:00
status = SWITCH_STATUS_SUCCESS ;
2007-03-29 22:34:40 +00:00
2014-04-09 07:23:48 +00:00
if ( ( proceed = switch_regex_perform ( field_expanded , pattern , & re , ovector , sizeof ( ovector ) / sizeof ( ovector [ 0 ] ) ) ) ) {
match = switch_xml_child ( input , " match " ) ;
} else {
match = switch_xml_child ( input , " nomatch " ) ;
}
2008-05-27 04:30:03 +00:00
2014-04-09 07:23:48 +00:00
if ( match ) {
matches + + ;
2014-04-09 07:40:18 +00:00
for ( action = switch_xml_child ( match , " action " ) ; action ; action = action - > next ) {
2014-04-09 07:23:48 +00:00
char * adata = ( char * ) switch_xml_attr_soft ( action , " data " ) ;
char * func = ( char * ) switch_xml_attr_soft ( action , " function " ) ;
char * substituted = NULL ;
uint32_t len = 0 ;
char * odata = NULL ;
char * expanded = NULL ;
if ( strchr ( pattern , ' ( ' ) & & strchr ( adata , ' $ ' ) & & proceed > 0 ) {
len = ( uint32_t ) ( strlen ( data ) + strlen ( adata ) + 10 ) * proceed ;
if ( ! ( substituted = malloc ( len ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Memory Error! \n " ) ;
switch_regex_safe_free ( re ) ;
switch_safe_free ( field_expanded_alloc ) ;
goto done ;
}
memset ( substituted , 0 , len ) ;
switch_perform_substitution ( re , proceed , adata , field_expanded , substituted , len , ovector ) ;
odata = substituted ;
} else {
odata = adata ;
}
2007-03-29 22:34:40 +00:00
2014-04-09 07:23:48 +00:00
if ( event ) {
expanded = switch_event_expand_headers ( event , odata ) ;
} else {
expanded = switch_channel_expand_variables ( channel , odata ) ;
}
if ( expanded = = odata ) {
expanded = NULL ;
} else {
odata = expanded ;
}
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Handle %s:[%s] (%s:%s) \n " , func , odata , chan_lang ,
module_name ) ;
if ( ! strcasecmp ( func , " play-file " ) ) {
status = switch_ivr_play_file ( session , NULL , odata , args ) ;
} else if ( ! strcasecmp ( func , " phrase " ) ) {
char * name = ( char * ) switch_xml_attr_soft ( action , " phrase " ) ;
status = switch_ivr_phrase_macro ( session , name , odata , chan_lang , args ) ;
} else if ( ! strcasecmp ( func , " break " ) ) {
2014-04-09 07:35:15 +00:00
done = 1 ; /* don't break or we leak memory */
2014-04-09 07:23:48 +00:00
} else if ( ! strcasecmp ( func , " execute " ) ) {
switch_application_interface_t * app ;
char * cmd , * cmd_args ;
status = SWITCH_STATUS_FALSE ;
cmd = switch_core_session_strdup ( session , odata ) ;
cmd_args = switch_separate_paren_args ( cmd ) ;
if ( ! cmd_args ) {
cmd_args = " " ;
2007-03-29 22:34:40 +00:00
}
2014-04-09 07:23:48 +00:00
if ( ( app = switch_loadable_module_get_application_interface ( cmd ) ) ! = NULL ) {
status = switch_core_session_exec ( session , app , cmd_args ) ;
UNPROTECT_INTERFACE ( app ) ;
2010-03-03 20:49:38 +00:00
} else {
2014-04-09 07:23:48 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Invalid Application %s \n " , cmd ) ;
2010-03-03 20:49:38 +00:00
}
2014-04-09 07:23:48 +00:00
} else if ( ! strcasecmp ( func , " say " ) ) {
switch_say_interface_t * si ;
if ( ( si = switch_loadable_module_get_say_interface ( module_name ) ) ) {
char * say_type = ( char * ) switch_xml_attr_soft ( action , " type " ) ;
char * say_method = ( char * ) switch_xml_attr_soft ( action , " method " ) ;
char * say_gender = ( char * ) switch_xml_attr_soft ( action , " gender " ) ;
switch_say_args_t say_args = { 0 } ;
say_args . type = switch_ivr_get_say_type_by_name ( say_type ) ;
say_args . method = switch_ivr_get_say_method_by_name ( say_method ) ;
say_args . gender = switch_ivr_get_say_gender_by_name ( say_gender ) ;
status = si - > say_function ( session , odata , & say_args , args ) ;
2007-03-29 22:34:40 +00:00
} else {
2014-04-09 07:23:48 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Invalid SAY Interface [%s]! \n " , module_name ) ;
2007-03-29 22:34:40 +00:00
}
2014-04-09 07:23:48 +00:00
} else if ( ! strcasecmp ( func , " speak-text " ) ) {
const char * my_tts_engine = switch_xml_attr ( action , " tts-engine " ) ;
const char * my_tts_voice = switch_xml_attr ( action , " tts-voice " ) ;
2010-02-06 03:38:24 +00:00
2014-04-09 07:23:48 +00:00
if ( ! my_tts_engine ) {
my_tts_engine = tts_engine ;
2007-03-29 22:34:40 +00:00
}
2008-09-09 18:24:13 +00:00
2014-04-09 07:23:48 +00:00
if ( ! my_tts_voice ) {
my_tts_voice = tts_voice ;
}
if ( zstr ( tts_engine ) | | zstr ( tts_voice ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " TTS is not configured \n " ) ;
} else {
status = switch_ivr_speak_text ( session , my_tts_engine , my_tts_voice , odata , args ) ;
}
2007-03-29 22:34:40 +00:00
}
2013-11-27 00:38:30 +00:00
2014-04-09 07:23:48 +00:00
switch_ivr_sleep ( session , pause , SWITCH_FALSE , NULL ) ;
switch_safe_free ( expanded ) ;
switch_safe_free ( substituted ) ;
2014-04-09 07:40:18 +00:00
if ( done | | status ! = SWITCH_STATUS_SUCCESS ) break ;
2008-05-16 18:40:39 +00:00
}
2014-04-09 07:23:48 +00:00
}
2008-05-27 04:30:03 +00:00
2014-04-09 07:23:48 +00:00
switch_regex_safe_free ( re ) ;
2014-04-09 07:26:36 +00:00
switch_safe_free ( field_expanded_alloc ) ;
2014-04-09 07:23:48 +00:00
2014-04-09 07:40:18 +00:00
if ( done | | status ! = SWITCH_STATUS_SUCCESS
| | ( match & & do_break & & switch_true ( do_break ) ) ) {
2007-03-29 22:34:40 +00:00
break ;
}
input = input - > next ;
}
2010-02-06 03:38:24 +00:00
done :
2008-05-27 04:30:03 +00:00
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2008-01-23 20:59:25 +00:00
if ( hint_data ) {
switch_event_destroy ( & hint_data ) ;
}
2014-04-09 04:48:09 +00:00
if ( searched & & ! matches ) {
2010-02-18 19:54:58 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " Macro [%s]: '%s' did not match any patterns \n " , macro_name , data ) ;
2007-11-07 23:37:22 +00:00
}
2007-10-12 22:08:30 +00:00
if ( old_sound_prefix ) {
switch_channel_set_variable ( channel , " sound_prefix " , old_sound_prefix ) ;
}
2011-04-20 17:09:03 +00:00
if ( local_sound_prefix_enforced = = SWITCH_TRUE ) {
switch_channel_set_variable ( channel , " sound_prefix_enforced " , NULL ) ;
}
2007-03-29 22:34:40 +00:00
if ( xml ) {
switch_xml_free ( xml ) ;
}
2007-11-07 23:37:22 +00:00
2007-03-29 22:34:40 +00:00
return status ;
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_record_file ( switch_core_session_t * session ,
2007-12-29 23:15:57 +00:00
switch_file_handle_t * fh , const char * file , switch_input_args_t * args , uint32_t limit )
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 ) ;
2008-05-27 04:30:03 +00:00
switch_dtmf_t dtmf = { 0 } ;
2007-03-29 22:34:40 +00:00
switch_file_handle_t lfh = { 0 } ;
switch_frame_t * read_frame ;
2009-04-25 13:05:39 +00:00
switch_codec_t codec , write_codec = { 0 } ;
2007-03-29 22:34:40 +00:00
char * codec_name ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2007-11-01 11:28:26 +00:00
const char * p ;
2007-03-29 22:34:40 +00:00
const char * vval ;
time_t start = 0 ;
uint32_t org_silence_hits = 0 ;
2009-01-10 03:52:28 +00:00
int asis = 0 ;
2010-10-27 00:34:47 +00:00
int32_t sample_start = 0 ;
2010-03-10 23:40:14 +00:00
int waste_resources = 0 , fill_cng = 0 ;
2010-02-06 03:38:24 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
2009-04-25 13:05:39 +00:00
switch_frame_t write_frame = { 0 } ;
2009-04-25 22:10:40 +00:00
unsigned char write_buf [ SWITCH_RECOMMENDED_BUFFER_SIZE ] = { 0 } ;
2009-08-21 22:29:44 +00:00
switch_event_t * event ;
2009-11-06 23:29:36 +00:00
int divisor = 0 ;
2009-11-17 21:40:09 +00:00
int file_flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT ;
2011-01-24 15:43:16 +00:00
int restart_limit_on_dtmf = 0 ;
2011-08-16 21:11:18 +00:00
const char * prefix , * var ;
2015-02-27 19:55:54 +00:00
2012-12-10 16:56:07 +00:00
2013-12-09 22:42:12 +00:00
if ( switch_channel_pre_answer ( channel ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_FALSE ;
}
2010-01-26 18:20:09 +00:00
prefix = switch_channel_get_variable ( channel , " sound_prefix " ) ;
2010-02-06 03:38:24 +00:00
2010-01-26 18:20:09 +00:00
if ( ! prefix ) {
prefix = SWITCH_GLOBAL_dirs . sounds_dir ;
}
2009-04-25 13:05:39 +00:00
2013-12-09 22:42:12 +00:00
if ( ! switch_channel_media_ready ( channel ) ) {
2009-02-10 19:09:06 +00:00
return SWITCH_STATUS_FALSE ;
}
2013-12-09 22:42:12 +00:00
switch_core_session_get_read_impl ( session , & read_impl ) ;
2010-02-06 03:38:24 +00:00
2013-12-09 22:42:12 +00:00
if ( ! ( divisor = read_impl . actual_samples_per_second / 8000 ) ) {
divisor = 1 ;
2009-02-10 19:09:06 +00:00
}
2008-01-28 07:26:10 +00:00
2012-12-10 16:56:07 +00:00
arg_recursion_check_start ( args ) ;
2007-03-29 22:34:40 +00:00
if ( ! fh ) {
fh = & lfh ;
}
2009-02-10 19:09:06 +00:00
fh - > channels = read_impl . number_of_channels ;
fh - > native_rate = read_impl . actual_samples_per_second ;
2007-03-29 22:34:40 +00:00
2010-10-27 00:34:47 +00:00
if ( fh - > samples > 0 ) {
sample_start = fh - > samples ;
fh - > samples = 0 ;
}
2009-06-12 15:59:19 +00:00
if ( ( vval = switch_channel_get_variable ( channel , " record_sample_rate " ) ) ) {
int tmp = 0 ;
tmp = atoi ( vval ) ;
2009-06-12 16:06:34 +00:00
if ( switch_is_valid_rate ( tmp ) ) {
2009-06-12 15:59:19 +00:00
fh - > samplerate = tmp ;
}
}
2013-11-27 00:38:30 +00:00
2010-03-10 23:40:14 +00:00
if ( ( vval = switch_channel_get_variable ( channel , " record_fill_cng " ) ) ) {
2010-03-10 23:53:12 +00:00
if ( ! strcasecmp ( vval , " true " ) ) {
2010-03-10 23:40:14 +00:00
fill_cng = 1400 ;
} else {
if ( ( fill_cng = atoi ( vval ) ) < 0 ) {
fill_cng = 0 ;
}
}
}
2013-11-27 00:38:30 +00:00
2009-06-12 15:59:19 +00:00
2009-04-26 14:39:03 +00:00
if ( ( vval = switch_channel_get_variable ( channel , " record_waste_resources " ) ) ) {
2010-02-06 03:38:24 +00:00
2010-03-10 23:53:12 +00:00
if ( ! strcasecmp ( vval , " true " ) ) {
2009-04-26 14:39:03 +00:00
waste_resources = 1400 ;
} else {
if ( ( waste_resources = atoi ( vval ) ) < 0 ) {
waste_resources = 0 ;
}
}
2010-03-10 23:40:14 +00:00
}
2009-04-26 14:39:03 +00:00
2010-03-10 23:40:14 +00:00
if ( fill_cng | | waste_resources ) {
2009-04-25 13:05:39 +00:00
if ( switch_core_codec_init ( & write_codec ,
" L16 " ,
NULL ,
2015-03-19 19:26:47 +00:00
NULL ,
2009-04-25 13:05:39 +00:00
read_impl . actual_samples_per_second ,
read_impl . microseconds_per_packet / 1000 ,
read_impl . number_of_channels ,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE , 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_DEBUG , " Raw Codec Activated, ready to waste resources! \n " ) ;
2009-04-25 13:05:39 +00:00
write_frame . data = write_buf ;
write_frame . buflen = sizeof ( write_buf ) ;
write_frame . datalen = read_impl . decoded_bytes_per_packet ;
write_frame . samples = write_frame . datalen / 2 ;
write_frame . codec = & write_codec ;
} else {
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2009-04-25 13:05:39 +00:00
return SWITCH_STATUS_FALSE ;
}
}
2010-02-06 03:38:24 +00:00
2009-01-10 03:52:28 +00:00
if ( ! strstr ( file , SWITCH_URL_SEPARATOR ) ) {
char * ext ;
2009-09-16 20:46:36 +00:00
2009-01-10 03:52:28 +00:00
if ( ! switch_is_file_path ( file ) ) {
2009-09-16 20:46:36 +00:00
char * tfile = NULL ;
char * e ;
2015-03-18 22:58:23 +00:00
if ( * file = = ' { ' ) {
2009-09-16 20:46:36 +00:00
tfile = switch_core_session_strdup ( session , file ) ;
2015-03-18 22:58:23 +00:00
while ( * file = = ' { ' ) {
if ( ( e = switch_find_end_paren ( tfile , ' { ' , ' } ' ) ) ) {
* e = ' \0 ' ;
file = e + 1 ;
while ( * file = = ' ' ) file + + ;
} else {
tfile = NULL ;
break ;
}
2009-09-16 20:46:36 +00:00
}
}
2015-03-18 22:58:23 +00:00
file = switch_core_session_sprintf ( session , " %s%s%s%s%s " , switch_str_nil ( tfile ) , tfile ? " } " : " " , prefix , SWITCH_PATH_SEPARATOR , file ) ;
2009-01-10 03:52:28 +00:00
}
if ( ( ext = strrchr ( file , ' . ' ) ) ) {
ext + + ;
} else {
2009-02-10 19:09:06 +00:00
ext = read_impl . iananame ;
2009-01-10 03:52:28 +00:00
file = switch_core_session_sprintf ( session , " %s.%s " , file , ext ) ;
asis = 1 ;
}
}
2014-10-09 21:53:38 +00:00
if ( asis & & read_impl . encoded_bytes_per_packet = = 0 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " %s cannot play or record native files with variable length data \n " , switch_channel_get_name ( channel ) ) ;
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_TRUE ) ;
arg_recursion_check_stop ( args ) ;
return SWITCH_STATUS_GENERR ;
}
2009-02-06 20:44:53 +00:00
vval = switch_channel_get_variable ( channel , " enable_file_write_buffering " ) ;
2009-02-07 21:22:12 +00:00
if ( ! vval | | switch_true ( vval ) ) {
2009-02-06 20:44:53 +00:00
fh - > pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN ;
}
2009-01-10 03:52:28 +00:00
2010-10-04 23:23:43 +00:00
if ( switch_test_flag ( fh , SWITCH_FILE_WRITE_APPEND ) | | ( ( p = switch_channel_get_variable ( channel , " RECORD_APPEND " ) ) & & switch_true ( p ) ) ) {
2009-11-17 21:40:09 +00:00
file_flags | = SWITCH_FILE_WRITE_APPEND ;
}
2010-10-27 00:34:47 +00:00
if ( switch_test_flag ( fh , SWITCH_FILE_WRITE_OVER ) | | ( ( p = switch_channel_get_variable ( channel , " RECORD_WRITE_OVER " ) ) & & switch_true ( p ) ) ) {
file_flags | = SWITCH_FILE_WRITE_OVER ;
}
2010-01-26 18:20:09 +00:00
if ( ! fh - > prefix ) {
fh - > prefix = prefix ;
}
2010-02-06 03:38:24 +00:00
2015-02-27 19:55:54 +00:00
if ( switch_channel_test_flag ( channel , CF_VIDEO ) ) {
2015-05-23 01:27:14 +00:00
switch_vid_params_t vid_params = { 0 } ;
2015-02-27 19:55:54 +00:00
file_flags | = SWITCH_FILE_FLAG_VIDEO ;
2015-03-03 00:05:59 +00:00
switch_channel_set_flag_recursive ( channel , CF_VIDEO_DECODED_READ ) ;
2015-05-23 01:27:14 +00:00
fh - > mm . fps = switch_core_media_get_video_fps ( session ) ;
switch_core_media_get_vid_params ( session , & vid_params ) ;
fh - > mm . vw = vid_params . width ;
fh - > mm . vh = vid_params . height ;
2015-02-27 19:55:54 +00:00
}
2010-02-06 03:38:24 +00:00
if ( switch_core_file_open ( fh , file , fh - > channels , read_impl . actual_samples_per_second , file_flags , NULL ) ! = SWITCH_STATUS_SUCCESS ) {
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 ) ;
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2007-03-29 22:34:40 +00:00
return SWITCH_STATUS_GENERR ;
}
2015-02-27 19:55:54 +00:00
if ( switch_core_file_has_video ( fh ) ) {
switch_channel_set_flag ( channel , CF_VIDEO_ECHO ) ;
switch_core_media_set_video_file ( session , fh , SWITCH_RW_READ ) ;
2015-06-25 18:33:47 +00:00
} else if ( switch_channel_test_flag ( channel , CF_VIDEO ) ) {
switch_channel_set_flag ( channel , CF_VIDEO_BLANK ) ;
2015-02-27 19:55:54 +00:00
}
2007-03-29 22:34:40 +00:00
2010-10-27 00:34:47 +00:00
if ( sample_start > 0 ) {
uint32_t pos = 0 ;
switch_core_file_seek ( fh , & pos , sample_start , SEEK_SET ) ;
2013-11-27 00:38:30 +00:00
switch_clear_flag ( fh , SWITCH_FILE_SEEK ) ;
2010-10-27 00:34:47 +00:00
fh - > samples = 0 ;
}
2009-01-10 16:04:34 +00:00
if ( switch_test_flag ( fh , SWITCH_FILE_NATIVE ) ) {
asis = 1 ;
}
2013-11-27 00:38:30 +00:00
2011-01-24 15:43:16 +00:00
restart_limit_on_dtmf = switch_true ( switch_channel_get_variable ( channel , " record_restart_limit_on_dtmf " ) ) ;
2009-01-10 16:04:34 +00:00
2007-03-29 22:34:40 +00:00
if ( ( p = switch_channel_get_variable ( channel , " RECORD_TITLE " ) ) ) {
2007-11-01 11:28:26 +00:00
vval = switch_core_session_strdup ( session , p ) ;
2007-03-29 22:34:40 +00:00
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 " ) ) ) {
2007-11-01 11:28:26 +00:00
vval = switch_core_session_strdup ( session , p ) ;
2007-03-29 22:34:40 +00:00
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 " ) ) ) {
2007-11-01 11:28:26 +00:00
vval = switch_core_session_strdup ( session , p ) ;
2007-03-29 22:34:40 +00:00
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 " ) ) ) {
2007-11-01 11:28:26 +00:00
vval = switch_core_session_strdup ( session , p ) ;
2007-03-29 22:34:40 +00:00
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 " ) ) ) {
2007-11-01 11:28:26 +00:00
vval = switch_core_session_strdup ( session , p ) ;
2007-03-29 22:34:40 +00:00
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 " ) ) ) {
2007-11-01 11:28:26 +00:00
vval = switch_core_session_strdup ( session , p ) ;
2007-03-29 22:34:40 +00:00
switch_core_file_set_string ( fh , SWITCH_AUDIO_COL_STR_DATE , vval ) ;
switch_channel_set_variable ( channel , " RECORD_DATE " , NULL ) ;
}
2015-04-02 23:03:41 +00:00
switch_channel_set_variable ( channel , " silence_hits_exhausted " , " false " ) ;
2009-01-10 03:52:28 +00:00
if ( ! asis ) {
codec_name = " L16 " ;
if ( switch_core_codec_init ( & codec ,
codec_name ,
NULL ,
2015-03-19 19:26:47 +00:00
NULL ,
2009-02-10 19:09:06 +00:00
read_impl . actual_samples_per_second ,
read_impl . microseconds_per_packet / 1000 ,
read_impl . number_of_channels ,
2009-01-10 03:52:28 +00:00
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE , 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_DEBUG , " Raw Codec Activated \n " ) ;
2009-01-10 03:52:28 +00:00
switch_core_session_set_read_codec ( session , & codec ) ;
} else {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR ,
2009-01-10 03:52:28 +00:00
" Raw Codec Activation Failed %s@%uhz %u channels %dms \n " , codec_name , fh - > samplerate ,
2009-02-10 19:09:06 +00:00
fh - > channels , read_impl . microseconds_per_packet / 1000 ) ;
2015-02-27 19:55:54 +00:00
if ( switch_core_file_has_video ( fh ) ) {
2015-03-03 00:05:59 +00:00
switch_channel_clear_flag ( channel , CF_VIDEO_ECHO ) ;
switch_channel_clear_flag_recursive ( channel , CF_VIDEO_DECODED_READ ) ;
2015-02-27 19:55:54 +00:00
switch_core_media_set_video_file ( session , NULL , SWITCH_RW_READ ) ;
}
2015-06-25 18:33:47 +00:00
switch_channel_clear_flag ( channel , CF_VIDEO_BLANK ) ;
2009-01-10 03:52:28 +00:00
switch_core_file_close ( fh ) ;
2015-02-27 19:55:54 +00:00
2009-01-10 03:52:28 +00:00
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_TRUE ) ;
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2009-01-10 03:52:28 +00:00
return SWITCH_STATUS_GENERR ;
}
2007-03-29 22:34:40 +00:00
}
if ( limit ) {
2009-01-25 21:23:07 +00:00
start = switch_epoch_time_now ( NULL ) ;
2007-03-29 22:34:40 +00:00
}
2010-02-06 03:38:24 +00:00
2007-03-29 22:34:40 +00:00
if ( fh - > thresh ) {
2009-01-10 03:52:28 +00:00
if ( asis ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " Can't detect silence on a native recording. \n " ) ;
2007-03-29 22:34:40 +00:00
} else {
2009-01-10 03:52:28 +00:00
if ( fh - > silence_hits ) {
2009-02-10 19:09:06 +00:00
fh - > silence_hits = fh - > samplerate * fh - > silence_hits / read_impl . samples_per_packet ;
2009-01-10 03:52:28 +00:00
} else {
2009-02-10 19:09:06 +00:00
fh - > silence_hits = fh - > samplerate * 3 / read_impl . samples_per_packet ;
2009-01-10 03:52:28 +00:00
}
org_silence_hits = fh - > silence_hits ;
2007-03-29 22:34:40 +00:00
}
}
2009-08-21 22:29:44 +00:00
if ( switch_event_create ( & event , SWITCH_EVENT_RECORD_START ) = = SWITCH_STATUS_SUCCESS ) {
switch_channel_event_set_data ( channel , event ) ;
2009-11-12 15:12:32 +00:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Record-File-Path " , file ) ;
2009-08-21 22:29:44 +00:00
switch_event_fire ( & event ) ;
}
2008-05-27 04:30:03 +00:00
for ( ; ; ) {
2007-03-29 22:34:40 +00:00
switch_size_t len ;
2008-05-27 04:30:03 +00:00
2007-07-02 20:16:08 +00:00
if ( ! switch_channel_ready ( channel ) ) {
status = SWITCH_STATUS_FALSE ;
break ;
}
2007-06-25 21:25:33 +00:00
if ( switch_channel_test_flag ( channel , CF_BREAK ) ) {
switch_channel_clear_flag ( channel , CF_BREAK ) ;
2007-07-02 20:16:08 +00:00
status = SWITCH_STATUS_BREAK ;
2007-06-25 21:25:33 +00:00
break ;
}
2008-05-27 04:30:03 +00:00
2009-10-12 22:23:55 +00:00
switch_ivr_parse_all_events ( session ) ;
2007-03-29 22:34:40 +00:00
2009-01-25 21:23:07 +00:00
if ( start & & ( switch_epoch_time_now ( NULL ) - start ) > limit ) {
2007-03-29 22:34:40 +00:00
break ;
}
2011-01-24 20:04:26 +00:00
if ( args ) {
2007-03-29 22:34:40 +00:00
/*
2013-11-27 00:38:30 +00:00
dtmf handler function you can hook up to be executed when a digit is dialed during playback
2010-02-06 03:38:24 +00:00
if you return anything but SWITCH_STATUS_SUCCESS the playback will stop .
*/
2007-03-29 22:34:40 +00:00
if ( switch_channel_has_dtmf ( channel ) ) {
2011-01-24 15:43:16 +00:00
if ( limit & & restart_limit_on_dtmf ) {
start = switch_epoch_time_now ( NULL ) ;
}
2010-10-04 23:23:43 +00:00
if ( ! args - > input_callback & & ! args - > buf & & ! args - > dmachine ) {
2007-03-29 22:34:40 +00:00
status = SWITCH_STATUS_BREAK ;
break ;
}
2007-12-22 00:32:20 +00:00
switch_channel_dequeue_dtmf ( channel , & dtmf ) ;
2010-10-04 23:23:43 +00:00
if ( args - > dmachine ) {
char ds [ 2 ] = { dtmf . digit , ' \0 ' } ;
if ( ( status = switch_ivr_dmachine_feed ( args - > dmachine , ds , NULL ) ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
2013-11-27 00:38:30 +00:00
}
2012-01-05 15:39:18 +00:00
if ( args - > input_callback ) {
2008-05-27 04:30:03 +00:00
status = args - > input_callback ( session , ( void * ) & dtmf , SWITCH_INPUT_TYPE_DTMF , args - > buf , args - > buflen ) ;
2012-01-05 22:01:27 +00:00
} else if ( args - > buf ) {
2010-08-23 20:54:23 +00:00
* ( ( char * ) args - > buf ) = dtmf . digit ;
2007-03-29 22:34:40 +00:00
status = SWITCH_STATUS_BREAK ;
}
}
if ( args - > input_callback ) {
2007-05-14 23:50:38 +00:00
switch_event_t * event = NULL ;
2013-07-01 19:31:43 +00:00
switch_status_t ostatus ;
2007-05-14 23:50:38 +00:00
2009-02-21 23:19:58 +00:00
if ( switch_core_session_dequeue_event ( session , & event , SWITCH_FALSE ) = = SWITCH_STATUS_SUCCESS ) {
2013-07-01 19:31:43 +00:00
if ( ( ostatus = args - > input_callback ( session , event , SWITCH_INPUT_TYPE_EVENT , args - > buf , args - > buflen ) ) ! = SWITCH_STATUS_SUCCESS ) {
status = ostatus ;
}
2013-11-27 00:38:30 +00:00
2007-03-29 22:34:40 +00:00
switch_event_destroy ( & event ) ;
}
}
if ( status ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
}
2008-05-08 19:19:47 +00:00
status = switch_core_session_read_frame ( session , & read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2007-03-29 22:34:40 +00:00
if ( ! SWITCH_READ_ACCEPTABLE ( status ) ) {
break ;
}
2010-10-04 23:23:43 +00:00
if ( args & & args - > dmachine ) {
if ( ( status = switch_ivr_dmachine_ping ( args - > dmachine , NULL ) ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
}
2007-10-02 00:09:49 +00:00
if ( args & & ( args - > read_frame_callback ) ) {
2010-10-04 23:23:43 +00:00
if ( ( status = args - > read_frame_callback ( session , read_frame , args - > user_data ) ) ! = SWITCH_STATUS_SUCCESS ) {
2007-10-02 00:09:49 +00:00
break ;
}
}
2009-01-10 03:52:28 +00:00
if ( ! asis & & fh - > thresh ) {
2007-03-29 22:34:40 +00:00
int16_t * fdata = ( int16_t * ) read_frame - > data ;
uint32_t samples = read_frame - > datalen / sizeof ( * fdata ) ;
uint32_t score , count = 0 , j = 0 ;
double energy = 0 ;
2009-11-06 23:29:36 +00:00
2008-05-27 04:30:03 +00:00
2014-06-12 23:49:37 +00:00
for ( count = 0 ; count < samples * read_impl . number_of_channels ; count + + ) {
energy + = abs ( fdata [ j + + ] ) ;
2007-03-29 22:34:40 +00:00
}
2007-11-24 21:48:25 +00:00
score = ( uint32_t ) ( energy / ( samples / divisor ) ) ;
2009-11-06 23:29:36 +00:00
2007-03-29 22:34:40 +00:00
if ( score < fh - > thresh ) {
if ( ! - - fh - > silence_hits ) {
2015-04-02 23:03:41 +00:00
switch_channel_set_variable ( channel , " silence_hits_exhausted " , " true " ) ;
2007-03-29 22:34:40 +00:00
break ;
}
} else {
fh - > silence_hits = org_silence_hits ;
}
}
2010-03-14 23:54:24 +00:00
if ( fill_cng ) {
2014-06-12 23:49:37 +00:00
switch_generate_sln_silence ( ( int16_t * ) write_frame . data , write_frame . samples , read_impl . number_of_channels , fill_cng ) ;
2010-03-14 23:54:24 +00:00
} else if ( waste_resources ) {
2014-06-12 23:49:37 +00:00
switch_generate_sln_silence ( ( int16_t * ) write_frame . data , write_frame . samples , read_impl . number_of_channels , waste_resources ) ;
2010-03-10 23:40:14 +00:00
}
2007-12-12 21:30:55 +00:00
if ( ! switch_test_flag ( fh , SWITCH_FILE_PAUSE ) & & ! switch_test_flag ( read_frame , SFF_CNG ) ) {
2007-11-26 23:41:00 +00:00
int16_t * data = read_frame - > data ;
2014-06-12 17:06:33 +00:00
len = ( switch_size_t ) asis ? read_frame - > datalen : read_frame - > datalen / 2 / fh - > channels ;
2010-02-06 03:38:24 +00:00
2007-11-26 23:41:00 +00:00
if ( switch_core_file_write ( fh , data , & len ) ! = SWITCH_STATUS_SUCCESS ) {
2007-03-29 22:34:40 +00:00
break ;
}
2010-03-14 23:54:24 +00:00
} else if ( switch_test_flag ( read_frame , SFF_CNG ) & & fill_cng ) {
2014-06-12 17:06:33 +00:00
len = write_frame . datalen / 2 / fh - > channels ;
2010-03-10 23:40:14 +00:00
if ( switch_core_file_write ( fh , write_frame . data , & len ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
2013-11-27 00:38:30 +00:00
}
2007-03-29 22:34:40 +00:00
}
2009-04-25 13:05:39 +00:00
if ( waste_resources ) {
if ( switch_core_session_write_frame ( session , & write_frame , SWITCH_IO_FLAG_NONE , 0 ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
}
}
2010-03-14 23:54:24 +00:00
if ( fill_cng | | waste_resources ) {
2009-04-25 13:05:39 +00:00
switch_core_codec_destroy ( & write_codec ) ;
2007-03-29 22:34:40 +00:00
}
2015-02-27 19:55:54 +00:00
if ( switch_core_file_has_video ( fh ) ) {
2015-03-03 00:05:59 +00:00
switch_channel_clear_flag ( channel , CF_VIDEO_ECHO ) ;
switch_channel_clear_flag_recursive ( channel , CF_VIDEO_DECODED_READ ) ;
2015-02-27 19:55:54 +00:00
switch_core_media_set_video_file ( session , NULL , SWITCH_RW_READ ) ;
}
2015-06-25 18:33:47 +00:00
switch_channel_clear_flag ( channel , CF_VIDEO_BLANK ) ;
2007-03-29 22:34:40 +00:00
switch_core_file_close ( fh ) ;
2009-10-13 22:29:20 +00:00
2011-08-16 21:11:18 +00:00
if ( ( var = switch_channel_get_variable ( channel , " record_post_process_exec_api " ) ) ) {
char * cmd = switch_core_session_strdup ( session , var ) ;
char * data , * expanded = NULL ;
switch_stream_handle_t stream = { 0 } ;
2013-11-27 00:38:30 +00:00
2011-08-16 21:11:18 +00:00
SWITCH_STANDARD_STREAM ( stream ) ;
2013-11-27 00:38:30 +00:00
2011-08-16 21:11:18 +00:00
if ( ( data = strchr ( cmd , ' : ' ) ) ) {
* data + + = ' \0 ' ;
expanded = switch_channel_expand_variables ( channel , data ) ;
}
2013-11-27 00:38:30 +00:00
2011-08-16 21:11:18 +00:00
switch_api_execute ( cmd , expanded , session , & stream ) ;
2013-11-27 00:38:30 +00:00
2011-08-16 21:11:18 +00:00
if ( expanded & & expanded ! = data ) {
free ( expanded ) ;
}
2013-11-27 00:38:30 +00:00
2011-08-16 21:11:18 +00:00
switch_safe_free ( stream . data ) ;
2013-11-27 00:38:30 +00:00
2011-08-16 21:11:18 +00:00
}
2011-09-21 16:05:33 +00:00
if ( read_impl . actual_samples_per_second ) {
2013-05-21 15:03:22 +00:00
switch_channel_set_variable_printf ( channel , " record_seconds " , " %d " , fh - > samples_out / fh - > native_rate ) ;
switch_channel_set_variable_printf ( channel , " record_ms " , " %d " , fh - > samples_out / ( fh - > native_rate / 1000 ) ) ;
2009-10-13 22:29:20 +00:00
}
switch_channel_set_variable_printf ( channel , " record_samples " , " %d " , fh - > samples_out ) ;
2011-02-25 16:55:33 +00:00
if ( switch_event_create ( & event , SWITCH_EVENT_RECORD_STOP ) = = SWITCH_STATUS_SUCCESS ) {
switch_channel_event_set_data ( channel , event ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Record-File-Path " , file ) ;
switch_event_fire ( & event ) ;
}
2009-01-09 20:34:01 +00:00
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_TRUE ) ;
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2007-03-29 22:34:40 +00:00
return status ;
}
2008-05-27 04:30:03 +00:00
static int teletone_handler ( teletone_generation_session_t * ts , teletone_tone_map_t * map )
2007-06-17 01:16:39 +00:00
{
switch_buffer_t * audio_buffer = ts - > user_data ;
int wrote ;
if ( ! audio_buffer ) {
return - 1 ;
}
wrote = teletone_mux_tones ( ts , map ) ;
switch_buffer_write ( audio_buffer , ts - > buffer , wrote * 2 ) ;
return 0 ;
}
2009-11-13 16:37:23 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_gentones ( switch_core_session_t * session , const char * script , int32_t loops , switch_input_args_t * args )
2007-06-17 01:16:39 +00:00
{
teletone_generation_session_t ts ;
2008-05-27 04:30:03 +00:00
switch_dtmf_t dtmf = { 0 } ;
2007-06-17 01:16:39 +00:00
switch_buffer_t * audio_buffer ;
switch_frame_t * read_frame = NULL ;
2009-02-10 19:09:06 +00:00
switch_codec_t write_codec = { 0 } ;
2007-09-24 15:52:32 +00:00
switch_frame_t write_frame = { 0 } ;
2008-02-14 17:12:17 +00:00
switch_byte_t data [ SWITCH_RECOMMENDED_BUFFER_SIZE ] ;
2008-01-28 07:26:10 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2010-02-06 03:38:24 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
switch_core_session_get_read_impl ( session , & read_impl ) ;
2007-06-17 01:16:39 +00:00
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
2007-06-17 01:16:39 +00:00
if ( switch_core_codec_init ( & write_codec ,
" L16 " ,
NULL ,
2015-03-19 19:26:47 +00:00
NULL ,
2009-02-10 19:09:06 +00:00
read_impl . actual_samples_per_second ,
read_impl . microseconds_per_packet / 1000 ,
2008-05-27 04:30:03 +00:00
1 , SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE ,
2007-06-17 01:16:39 +00:00
NULL , switch_core_session_get_pool ( session ) ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_FALSE ;
}
2012-12-10 16:56:07 +00:00
arg_recursion_check_start ( args ) ;
2007-09-24 15:52:32 +00:00
memset ( & ts , 0 , sizeof ( ts ) ) ;
2007-06-17 01:16:39 +00:00
write_frame . codec = & write_codec ;
write_frame . data = data ;
2009-05-29 18:48:54 +00:00
write_frame . buflen = sizeof ( data ) ;
2007-06-17 01:16:39 +00:00
switch_buffer_create_dynamic ( & audio_buffer , 512 , 1024 , 0 ) ;
teletone_init_session ( & ts , 0 , teletone_handler , audio_buffer ) ;
2009-02-10 19:09:06 +00:00
ts . rate = read_impl . actual_samples_per_second ;
2007-09-24 15:52:32 +00:00
ts . channels = 1 ;
2007-06-17 01:16:39 +00:00
teletone_run ( & ts , script ) ;
if ( loops ) {
switch_buffer_set_loops ( audio_buffer , loops ) ;
}
2008-05-27 04:30:03 +00:00
for ( ; ; ) {
2007-11-26 23:41:00 +00:00
switch_status_t status ;
2008-05-27 04:30:03 +00:00
2007-07-02 20:16:08 +00:00
if ( ! switch_channel_ready ( channel ) ) {
2008-05-27 04:30:03 +00:00
status = SWITCH_STATUS_FALSE ;
break ;
}
2007-07-02 20:16:08 +00:00
2007-06-25 21:25:33 +00:00
if ( switch_channel_test_flag ( channel , CF_BREAK ) ) {
switch_channel_clear_flag ( channel , CF_BREAK ) ;
2007-07-03 02:10:35 +00:00
status = SWITCH_STATUS_BREAK ;
2007-06-25 21:25:33 +00:00
break ;
}
2008-05-08 19:19:47 +00:00
status = switch_core_session_read_frame ( session , & read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2007-11-26 23:41:00 +00:00
2007-06-17 01:16:39 +00:00
if ( ! SWITCH_READ_ACCEPTABLE ( status ) ) {
break ;
}
2010-10-04 23:23:43 +00:00
if ( args & & args - > dmachine ) {
if ( ( status = switch_ivr_dmachine_ping ( args - > dmachine , NULL ) ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
}
2009-11-13 15:52:20 +00:00
if ( args & & ( args - > read_frame_callback ) ) {
2010-10-04 23:23:43 +00:00
if ( ( status = args - > read_frame_callback ( session , read_frame , args - > user_data ) ) ! = SWITCH_STATUS_SUCCESS ) {
2009-11-13 15:52:20 +00:00
break ;
}
}
2009-10-12 22:23:55 +00:00
switch_ivr_parse_all_events ( session ) ;
2008-09-25 19:53:43 +00:00
2011-01-24 20:04:26 +00:00
if ( args ) {
2008-05-24 00:02:18 +00:00
/*
2013-11-27 00:38:30 +00:00
dtmf handler function you can hook up to be executed when a digit is dialed during gentones
2010-02-06 03:38:24 +00:00
if you return anything but SWITCH_STATUS_SUCCESS the playback will stop .
*/
2008-05-24 00:02:18 +00:00
if ( switch_channel_has_dtmf ( channel ) ) {
2010-10-11 23:38:30 +00:00
if ( ! args - > input_callback & & ! args - > buf & & ! args - > dmachine ) {
2008-05-24 00:02:18 +00:00
status = SWITCH_STATUS_BREAK ;
break ;
}
switch_channel_dequeue_dtmf ( channel , & dtmf ) ;
2010-10-04 23:23:43 +00:00
if ( args - > dmachine ) {
char ds [ 2 ] = { dtmf . digit , ' \0 ' } ;
if ( ( status = switch_ivr_dmachine_feed ( args - > dmachine , ds , NULL ) ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
2013-11-27 00:38:30 +00:00
}
2012-01-05 15:39:18 +00:00
if ( args - > input_callback ) {
2008-05-27 04:30:03 +00:00
status = args - > input_callback ( session , ( void * ) & dtmf , SWITCH_INPUT_TYPE_DTMF , args - > buf , args - > buflen ) ;
2012-01-05 22:01:27 +00:00
} else if ( args - > buf ) {
2008-05-27 04:30:03 +00:00
* ( ( char * ) args - > buf ) = dtmf . digit ;
2008-05-24 00:02:18 +00:00
status = SWITCH_STATUS_BREAK ;
}
}
if ( args - > input_callback ) {
switch_event_t * event ;
2013-11-27 00:38:30 +00:00
2009-02-21 23:19:58 +00:00
if ( switch_core_session_dequeue_event ( session , & event , SWITCH_FALSE ) = = SWITCH_STATUS_SUCCESS ) {
2013-07-01 19:31:43 +00:00
switch_status_t ostatus = args - > input_callback ( session , event , SWITCH_INPUT_TYPE_EVENT , args - > buf , args - > buflen ) ;
if ( ostatus ! = SWITCH_STATUS_SUCCESS ) {
status = ostatus ;
}
2008-05-24 00:02:18 +00:00
switch_event_destroy ( & event ) ;
}
}
if ( status ! = SWITCH_STATUS_SUCCESS ) {
2007-10-02 00:09:49 +00:00
break ;
}
}
2009-02-10 19:09:06 +00:00
if ( ( write_frame . datalen = ( uint32_t ) switch_buffer_read_loop ( audio_buffer , write_frame . data , read_impl . decoded_bytes_per_packet ) ) < = 0 ) {
2007-06-17 01:16:39 +00:00
break ;
}
write_frame . samples = write_frame . datalen / 2 ;
2008-05-27 04:30:03 +00:00
2008-05-08 19:19:47 +00:00
if ( switch_core_session_write_frame ( session , & write_frame , SWITCH_IO_FLAG_NONE , 0 ) ! = SWITCH_STATUS_SUCCESS ) {
2007-06-17 01:16:39 +00:00
break ;
}
}
switch_core_codec_destroy ( & write_codec ) ;
switch_buffer_destroy ( & audio_buffer ) ;
teletone_destroy_session ( & ts ) ;
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2007-06-17 01:16:39 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2010-11-30 21:34:22 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_get_file_handle ( switch_core_session_t * session , switch_file_handle_t * * fh )
{
switch_file_handle_t * fhp ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
* fh = NULL ;
switch_core_session_io_read_lock ( session ) ;
2013-11-27 00:38:30 +00:00
2010-11-30 21:34:22 +00:00
if ( ( fhp = switch_channel_get_private ( channel , " __fh " ) ) ) {
* fh = fhp ;
return SWITCH_STATUS_SUCCESS ;
}
switch_core_session_io_rwunlock ( session ) ;
return SWITCH_STATUS_FALSE ;
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_release_file_handle ( switch_core_session_t * session , switch_file_handle_t * * fh )
{
* fh = NULL ;
switch_core_session_io_rwunlock ( session ) ;
return SWITCH_STATUS_SUCCESS ;
}
2007-06-17 01:16:39 +00:00
2007-03-29 22:34:40 +00:00
# define FILE_STARTSAMPLES 1024 * 32
# define FILE_BLOCKSIZE 1024 * 8
# define FILE_BUFSIZE 1024 * 64
2007-11-01 11:28:26 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_play_file ( switch_core_session_t * session , switch_file_handle_t * fh , const char * file , switch_input_args_t * args )
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 ) ;
2008-05-19 19:57:27 +00:00
int16_t * abuf = NULL ;
2008-05-27 04:30:03 +00:00
switch_dtmf_t dtmf = { 0 } ;
2015-10-20 16:00:12 +00:00
uint32_t interval = 0 , samples = 0 , framelen , sample_start = 0 , channels = 1 ;
2007-03-29 22:34:40 +00:00
uint32_t ilen = 0 ;
switch_size_t olen = 0 , llen = 0 ;
switch_frame_t write_frame = { 0 } ;
switch_timer_t timer = { 0 } ;
2009-04-29 15:08:53 +00:00
switch_codec_t codec = { 0 } ;
2007-03-29 22:34:40 +00:00
switch_memory_pool_t * pool = switch_core_session_get_pool ( session ) ;
char * codec_name ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
switch_file_handle_t lfh ;
const char * p ;
2011-04-22 21:43:29 +00:00
//char *title = "", *copyright = "", *software = "", *artist = "", *comment = "", *date = "";
2007-03-29 22:34:40 +00:00
char * ext ;
2007-11-01 11:28:26 +00:00
const char * prefix ;
const char * timer_name ;
const char * prebuf ;
2008-03-19 15:34:43 +00:00
const char * alt = NULL ;
2009-04-28 23:46:18 +00:00
const char * sleep_val ;
const char * play_delimiter_val ;
char play_delimiter = 0 ;
int sleep_val_i = 250 ;
2008-07-23 22:10:48 +00:00
int eof = 0 ;
switch_size_t bread = 0 ;
2008-08-12 19:12:38 +00:00
int l16 = 0 ;
2010-02-06 03:38:24 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
2009-04-28 23:46:18 +00:00
char * file_dup ;
char * argv [ 128 ] = { 0 } ;
int argc ;
int cur ;
2009-05-18 17:39:59 +00:00
int done = 0 ;
2010-06-18 23:07:31 +00:00
int timeout_samples = 0 ;
2013-01-13 06:18:44 +00:00
switch_bool_t timeout_as_success = SWITCH_FALSE ;
2010-06-18 23:07:31 +00:00
const char * var ;
2010-07-29 22:41:23 +00:00
int more_data = 0 ;
2011-02-25 16:55:33 +00:00
switch_event_t * event ;
2011-03-31 20:01:58 +00:00
uint32_t test_native = 0 , last_native = 0 ;
2013-09-20 18:34:57 +00:00
uint32_t buflen = 0 ;
2015-02-27 05:51:04 +00:00
int flags ;
2009-05-18 17:39:59 +00:00
2010-07-22 21:53:11 +00:00
if ( switch_channel_pre_answer ( channel ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_FALSE ;
}
2010-02-06 03:38:24 +00:00
switch_core_session_get_read_impl ( session , & read_impl ) ;
2007-03-29 22:34:40 +00:00
2010-06-18 23:07:31 +00:00
if ( ( var = switch_channel_get_variable ( channel , " playback_timeout_sec " ) ) ) {
int tmp = atoi ( var ) ;
if ( tmp > 1 ) {
timeout_samples = read_impl . actual_samples_per_second * tmp ;
}
}
2013-01-13 06:18:44 +00:00
if ( ( var = switch_channel_get_variable ( channel , " playback_timeout_as_success " ) ) ) {
if ( switch_true ( var ) ) {
timeout_as_success = SWITCH_TRUE ;
}
}
2009-04-28 23:46:18 +00:00
if ( ( play_delimiter_val = switch_channel_get_variable ( channel , " playback_delimiter " ) ) ) {
play_delimiter = * play_delimiter_val ;
if ( ( sleep_val = switch_channel_get_variable ( channel , " playback_sleep_val " ) ) ) {
int tmp = atoi ( sleep_val ) ;
if ( tmp > = 0 ) {
sleep_val_i = tmp ;
}
}
}
2007-03-29 22:34:40 +00:00
prefix = switch_channel_get_variable ( channel , " sound_prefix " ) ;
timer_name = switch_channel_get_variable ( channel , " timer_name " ) ;
2009-10-23 16:03:42 +00:00
if ( zstr ( file ) | | ! switch_channel_media_ready ( channel ) ) {
2009-04-28 23:46:18 +00:00
return SWITCH_STATUS_FALSE ;
2007-03-29 22:34:40 +00:00
}
2012-12-10 16:56:07 +00:00
arg_recursion_check_start ( args ) ;
2013-12-26 18:57:10 +00:00
if ( ! zstr ( read_impl . iananame ) & & ! strcasecmp ( read_impl . iananame , " l16 " ) ) {
2008-10-20 03:58:04 +00:00
l16 + + ;
}
2009-04-28 23:46:18 +00:00
if ( play_delimiter ) {
file_dup = switch_core_session_strdup ( session , file ) ;
argc = switch_separate_string ( file_dup , play_delimiter , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ;
} else {
argc = 1 ;
2010-02-06 03:38:24 +00:00
argv [ 0 ] = ( char * ) file ;
2009-04-28 23:46:18 +00:00
}
2011-03-31 23:29:49 +00:00
if ( ! fh ) {
fh = & lfh ;
memset ( fh , 0 , sizeof ( lfh ) ) ;
}
2013-11-27 00:38:30 +00:00
2011-03-31 23:29:49 +00:00
if ( fh - > samples > 0 ) {
sample_start = fh - > samples ;
fh - > samples = 0 ;
}
2013-11-27 00:38:30 +00:00
2013-09-20 18:34:57 +00:00
2010-02-06 03:38:24 +00:00
for ( cur = 0 ; switch_channel_ready ( channel ) & & ! done & & cur < argc ; cur + + ) {
2009-04-28 23:46:18 +00:00
file = argv [ cur ] ;
eof = 0 ;
2010-02-06 03:38:24 +00:00
2009-04-28 23:46:18 +00:00
if ( cur ) {
fh - > samples = sample_start = 0 ;
if ( sleep_val_i ) {
2012-04-11 13:39:01 +00:00
status = switch_ivr_sleep ( session , sleep_val_i , SWITCH_FALSE , args ) ;
2013-11-27 00:38:30 +00:00
if ( status ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
2009-04-28 23:46:18 +00:00
}
}
2010-02-06 03:38:24 +00:00
2009-04-28 23:46:18 +00:00
status = SWITCH_STATUS_SUCCESS ;
if ( ( alt = strchr ( file , ' : ' ) ) ) {
char * dup ;
2008-03-19 15:34:43 +00:00
2009-04-28 23:46:18 +00:00
if ( ! strncasecmp ( file , " phrase: " , 7 ) ) {
char * arg = NULL ;
const char * lang = switch_channel_get_variable ( channel , " language " ) ;
alt = file + 7 ;
dup = switch_core_session_strdup ( session , alt ) ;
2008-05-27 04:30:03 +00:00
2009-04-28 23:46:18 +00:00
if ( dup ) {
if ( ( arg = strchr ( dup , ' : ' ) ) ) {
* arg + + = ' \0 ' ;
}
2009-05-06 18:00:28 +00:00
if ( ( status = switch_ivr_phrase_macro ( session , dup , arg , lang , args ) ) ! = SWITCH_STATUS_SUCCESS ) {
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2009-05-06 18:00:28 +00:00
return status ;
2009-04-28 23:46:18 +00:00
}
continue ;
} else {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Invalid Args \n " ) ;
2009-04-28 23:46:18 +00:00
continue ;
2008-05-19 19:45:50 +00:00
}
2009-04-28 23:46:18 +00:00
} else if ( ! strncasecmp ( file , " say: " , 4 ) ) {
char * engine = NULL , * voice = NULL , * text = NULL ;
alt = file + 4 ;
dup = switch_core_session_strdup ( session , alt ) ;
engine = dup ;
2009-10-23 16:03:42 +00:00
if ( ! zstr ( engine ) ) {
2009-04-28 23:46:18 +00:00
if ( ( voice = strchr ( engine , ' : ' ) ) ) {
* voice + + = ' \0 ' ;
2009-10-23 16:03:42 +00:00
if ( ! zstr ( voice ) & & ( text = strchr ( voice , ' : ' ) ) ) {
2009-04-28 23:46:18 +00:00
* text + + = ' \0 ' ;
}
2008-05-21 20:32:51 +00:00
}
2008-03-19 15:34:43 +00:00
}
2008-05-21 20:32:51 +00:00
2009-10-23 16:03:42 +00:00
if ( ! zstr ( engine ) & & ! zstr ( voice ) & & ! zstr ( text ) ) {
2009-05-06 18:00:28 +00:00
if ( ( status = switch_ivr_speak_text ( session , engine , voice , text , args ) ) ! = SWITCH_STATUS_SUCCESS ) {
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2009-05-06 18:00:28 +00:00
return status ;
2009-04-28 23:46:18 +00:00
}
2010-02-15 20:16:06 +00:00
} else {
2009-04-28 23:46:18 +00:00
text = engine ;
engine = ( char * ) switch_channel_get_variable ( channel , " tts_engine " ) ;
voice = ( char * ) switch_channel_get_variable ( channel , " tts_voice " ) ;
if ( engine & & text ) {
2009-05-06 18:00:28 +00:00
if ( ( status = switch_ivr_speak_text ( session , engine , voice , text , args ) ) ! = SWITCH_STATUS_SUCCESS ) {
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2009-05-06 18:00:28 +00:00
return status ;
2009-04-28 23:46:18 +00:00
}
2010-02-15 20:16:06 +00:00
} else {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Invalid Args \n " ) ;
2009-04-28 23:46:18 +00:00
}
2008-04-07 20:22:38 +00:00
}
2010-02-15 20:16:06 +00:00
continue ;
2009-04-28 23:46:18 +00:00
}
}
if ( ! prefix ) {
prefix = SWITCH_GLOBAL_dirs . base_dir ;
}
if ( ! strstr ( file , SWITCH_URL_SEPARATOR ) ) {
if ( ! switch_is_file_path ( file ) ) {
2015-03-18 22:58:23 +00:00
char * tfile = NULL ;
2009-09-16 20:46:36 +00:00
char * e ;
2013-02-28 15:28:00 +00:00
2015-03-18 22:58:23 +00:00
if ( * file = = ' { ' ) {
tfile = switch_core_session_strdup ( session , file ) ;
while ( * file = = ' { ' ) {
if ( ( e = switch_find_end_paren ( tfile , ' { ' , ' } ' ) ) ) {
2013-02-28 15:28:00 +00:00
* e = ' \0 ' ;
file = e + 1 ;
2015-03-18 22:58:23 +00:00
while ( * file = = ' ' ) file + + ;
2013-02-28 15:28:00 +00:00
} else {
tfile = NULL ;
2015-03-18 22:58:23 +00:00
break ;
2013-02-28 15:28:00 +00:00
}
2009-09-16 20:46:36 +00:00
}
}
2015-03-18 22:58:23 +00:00
file = switch_core_session_sprintf ( session , " %s%s%s%s%s " , switch_str_nil ( tfile ) , tfile ? " } " : " " , prefix , SWITCH_PATH_SEPARATOR , file ) ;
2009-04-28 23:46:18 +00:00
}
if ( ( ext = strrchr ( file , ' . ' ) ) ) {
ext + + ;
2008-03-19 15:34:43 +00:00
} else {
2009-04-28 23:46:18 +00:00
ext = read_impl . iananame ;
file = switch_core_session_sprintf ( session , " %s.%s " , file , ext ) ;
2008-03-19 15:34:43 +00:00
}
}
2008-05-27 04:30:03 +00:00
2009-04-28 23:46:18 +00:00
if ( ( prebuf = switch_channel_get_variable ( channel , " stream_prebuffer " ) ) ) {
int maybe = atoi ( prebuf ) ;
if ( maybe > 0 ) {
fh - > prebuf = maybe ;
}
2007-03-29 22:34:40 +00:00
}
2010-02-06 03:38:24 +00:00
2010-01-26 18:20:09 +00:00
if ( ! fh - > prefix ) {
fh - > prefix = prefix ;
}
2015-02-27 05:51:04 +00:00
flags = SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT ;
if ( switch_channel_test_flag ( channel , CF_VIDEO ) ) {
flags | = SWITCH_FILE_FLAG_VIDEO ;
2015-03-27 20:59:51 +00:00
//switch_channel_set_flag_recursive(channel, CF_VIDEO_DECODED_READ);
2015-02-27 05:51:04 +00:00
}
2009-04-28 23:46:18 +00:00
if ( switch_core_file_open ( fh ,
file ,
read_impl . number_of_channels ,
2015-02-27 05:51:04 +00:00
read_impl . actual_samples_per_second , flags , NULL ) ! = SWITCH_STATUS_SUCCESS ) {
2009-12-18 23:19:53 +00:00
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_FALSE ) ;
2009-04-28 23:46:18 +00:00
status = SWITCH_STATUS_NOTFOUND ;
continue ;
}
2010-11-30 21:34:22 +00:00
2014-09-16 23:54:38 +00:00
switch_channel_audio_sync ( channel ) ;
2010-11-30 21:34:22 +00:00
switch_core_session_io_write_lock ( session ) ;
switch_channel_set_private ( channel , " __fh " , fh ) ;
switch_core_session_io_rwunlock ( session ) ;
2015-02-27 05:51:04 +00:00
if ( switch_core_file_has_video ( fh ) ) {
2015-02-27 19:55:54 +00:00
switch_core_media_set_video_file ( session , fh , SWITCH_RW_WRITE ) ;
2015-02-27 05:51:04 +00:00
}
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
if ( ! abuf ) {
2013-09-20 18:34:57 +00:00
buflen = write_frame . buflen = FILE_STARTSAMPLES * sizeof ( * abuf ) * fh - > channels ;
switch_zmalloc ( abuf , write_frame . buflen ) ;
2009-04-28 23:46:18 +00:00
write_frame . data = abuf ;
2007-06-09 23:02:38 +00:00
}
2009-04-28 23:46:18 +00:00
if ( sample_start > 0 ) {
uint32_t pos = 0 ;
switch_core_file_seek ( fh , & pos , 0 , SEEK_SET ) ;
switch_core_file_seek ( fh , & pos , sample_start , SEEK_CUR ) ;
2010-10-17 23:52:03 +00:00
switch_clear_flag ( fh , SWITCH_FILE_SEEK ) ;
2009-04-28 23:46:18 +00:00
}
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
if ( switch_core_file_get_string ( fh , SWITCH_AUDIO_COL_STR_TITLE , & p ) = = SWITCH_STATUS_SUCCESS ) {
2011-04-22 21:43:29 +00:00
//title = switch_core_session_strdup(session, p);
2009-04-28 23:46:18 +00:00
switch_channel_set_variable ( channel , " RECORD_TITLE " , p ) ;
}
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
if ( switch_core_file_get_string ( fh , SWITCH_AUDIO_COL_STR_COPYRIGHT , & p ) = = SWITCH_STATUS_SUCCESS ) {
2011-04-22 21:43:29 +00:00
//copyright = switch_core_session_strdup(session, p);
2009-04-28 23:46:18 +00:00
switch_channel_set_variable ( channel , " RECORD_COPYRIGHT " , p ) ;
}
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
if ( switch_core_file_get_string ( fh , SWITCH_AUDIO_COL_STR_SOFTWARE , & p ) = = SWITCH_STATUS_SUCCESS ) {
2011-04-22 21:43:29 +00:00
//software = switch_core_session_strdup(session, p);
2009-04-28 23:46:18 +00:00
switch_channel_set_variable ( channel , " RECORD_SOFTWARE " , p ) ;
}
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
if ( switch_core_file_get_string ( fh , SWITCH_AUDIO_COL_STR_ARTIST , & p ) = = SWITCH_STATUS_SUCCESS ) {
2011-04-22 21:43:29 +00:00
//artist = switch_core_session_strdup(session, p);
2009-04-28 23:46:18 +00:00
switch_channel_set_variable ( channel , " RECORD_ARTIST " , p ) ;
}
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
if ( switch_core_file_get_string ( fh , SWITCH_AUDIO_COL_STR_COMMENT , & p ) = = SWITCH_STATUS_SUCCESS ) {
2011-04-22 21:43:29 +00:00
//comment = switch_core_session_strdup(session, p);
2009-04-28 23:46:18 +00:00
switch_channel_set_variable ( channel , " RECORD_COMMENT " , p ) ;
}
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
if ( switch_core_file_get_string ( fh , SWITCH_AUDIO_COL_STR_DATE , & p ) = = SWITCH_STATUS_SUCCESS ) {
2011-04-22 21:43:29 +00:00
//date = switch_core_session_strdup(session, p);
2009-04-28 23:46:18 +00:00
switch_channel_set_variable ( channel , " RECORD_DATE " , p ) ;
}
2013-11-27 00:38:30 +00:00
2009-04-28 23:46:18 +00:00
interval = read_impl . microseconds_per_packet / 1000 ;
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
if ( ! fh - > audio_buffer ) {
switch_buffer_create_dynamic ( & fh - > audio_buffer , FILE_BLOCKSIZE , FILE_BUFSIZE , 0 ) ;
switch_assert ( fh - > audio_buffer ) ;
}
2007-03-29 22:34:40 +00:00
2011-03-31 20:01:58 +00:00
codec_name = " L16 " ;
2013-11-27 00:38:30 +00:00
2011-03-31 20:01:58 +00:00
if ( ! switch_core_codec_ready ( ( & codec ) ) ) {
if ( switch_core_codec_init ( & codec ,
codec_name ,
NULL ,
2015-03-19 19:26:47 +00:00
NULL ,
2011-03-31 20:01:58 +00:00
fh - > samplerate ,
2014-06-12 17:06:33 +00:00
interval , read_impl . number_of_channels ,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE , NULL , pool ) = = SWITCH_STATUS_SUCCESS ) {
2011-03-31 20:01:58 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) ,
2014-06-12 17:06:33 +00:00
SWITCH_LOG_DEBUG , " Codec Activated %s@%uhz %u channels %dms \n " ,
codec_name , fh - > samplerate , read_impl . number_of_channels , interval ) ;
2013-11-27 00:38:30 +00:00
2011-03-31 20:01:58 +00:00
} else {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG ,
2014-06-12 17:06:33 +00:00
" Raw Codec Activation Failed %s@%uhz %u channels %dms \n " , codec_name ,
fh - > samplerate , read_impl . number_of_channels , interval ) ;
2011-03-31 20:01:58 +00:00
switch_core_session_io_write_lock ( session ) ;
switch_channel_set_private ( channel , " __fh " , NULL ) ;
switch_core_session_io_rwunlock ( session ) ;
2013-11-27 00:38:30 +00:00
2015-02-27 05:51:04 +00:00
if ( switch_core_file_has_video ( fh ) ) {
2015-03-27 20:59:51 +00:00
//switch_channel_clear_flag_recursive(channel, CF_VIDEO_DECODED_READ);
2015-02-27 19:55:54 +00:00
switch_core_media_set_video_file ( session , NULL , SWITCH_RW_WRITE ) ;
2015-02-27 05:51:04 +00:00
}
2015-02-27 19:55:54 +00:00
2011-03-31 20:01:58 +00:00
switch_core_file_close ( fh ) ;
2013-11-27 00:38:30 +00:00
2011-03-31 20:01:58 +00:00
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_FALSE ) ;
status = SWITCH_STATUS_GENERR ;
continue ;
}
}
test_native = switch_test_flag ( fh , SWITCH_FILE_NATIVE ) ;
if ( test_native ) {
2009-04-28 23:46:18 +00:00
write_frame . codec = switch_core_session_get_read_codec ( session ) ;
samples = read_impl . samples_per_packet ;
framelen = read_impl . encoded_bytes_per_packet ;
2015-10-20 16:00:12 +00:00
channels = read_impl . number_of_channels ;
2014-10-09 21:53:38 +00:00
if ( framelen = = 0 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " %s cannot play or record native files with variable length data \n " , switch_channel_get_name ( channel ) ) ;
switch_core_session_io_write_lock ( session ) ;
switch_channel_set_private ( channel , " __fh " , NULL ) ;
switch_core_session_io_rwunlock ( session ) ;
2015-02-27 05:51:04 +00:00
if ( switch_core_file_has_video ( fh ) ) {
2015-03-27 20:59:51 +00:00
//switch_channel_clear_flag_recursive(channel, CF_VIDEO_DECODED_READ);
2015-02-27 19:55:54 +00:00
switch_core_media_set_video_file ( session , NULL , SWITCH_RW_WRITE ) ;
2015-02-27 05:51:04 +00:00
}
2014-10-09 21:53:38 +00:00
switch_core_file_close ( fh ) ;
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_FALSE ) ;
status = SWITCH_STATUS_GENERR ;
continue ;
}
2009-04-28 23:46:18 +00:00
} else {
write_frame . codec = & codec ;
samples = codec . implementation - > samples_per_packet ;
framelen = codec . implementation - > decoded_bytes_per_packet ;
2015-10-20 16:00:12 +00:00
channels = codec . implementation - > number_of_channels ;
2007-03-29 22:34:40 +00:00
}
2013-11-27 00:38:30 +00:00
2011-03-31 20:01:58 +00:00
last_native = test_native ;
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
if ( timer_name & & ! timer . samplecount ) {
uint32_t len ;
2007-03-29 22:34:40 +00:00
2015-10-20 16:00:12 +00:00
len = samples * 2 * channels ;
if ( switch_core_timer_init ( & timer , timer_name , interval , samples , pool ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Setup timer failed! \n " ) ;
2009-04-28 23:46:18 +00:00
switch_core_codec_destroy ( & codec ) ;
2010-11-30 21:34:22 +00:00
switch_core_session_io_write_lock ( session ) ;
switch_channel_set_private ( channel , " __fh " , NULL ) ;
switch_core_session_io_rwunlock ( session ) ;
2015-02-27 05:51:04 +00:00
if ( switch_core_file_has_video ( fh ) ) {
2015-03-27 20:59:51 +00:00
//switch_channel_clear_flag_recursive(channel, CF_VIDEO_DECODED_READ);
2015-02-27 19:55:54 +00:00
switch_core_media_set_video_file ( session , NULL , SWITCH_RW_WRITE ) ;
2015-02-27 05:51:04 +00:00
}
2009-04-28 23:46:18 +00:00
switch_core_file_close ( fh ) ;
2009-12-18 23:19:53 +00:00
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_FALSE ) ;
2009-04-28 23:46:18 +00:00
status = SWITCH_STATUS_GENERR ;
continue ;
}
2010-07-29 22:41:23 +00:00
switch_core_timer_sync ( & timer ) ; // Sync timer
2014-06-12 17:06:33 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG ,
" Setup timer success %u bytes per %d ms! %d ch \n " , len , interval , codec . implementation - > number_of_channels ) ;
2009-04-28 23:46:18 +00:00
}
write_frame . rate = fh - > samplerate ;
2015-07-22 05:29:36 +00:00
write_frame . channels = fh - > channels ;
2009-04-28 23:46:18 +00:00
if ( timer_name ) {
/* start a thread to absorb incoming audio */
switch_core_service_session ( session ) ;
2007-03-29 22:34:40 +00:00
}
2015-10-20 16:00:12 +00:00
ilen = samples * channels ;
2007-03-29 22:34:40 +00:00
2011-02-25 16:55:33 +00:00
if ( switch_event_create ( & event , SWITCH_EVENT_PLAYBACK_START ) = = SWITCH_STATUS_SUCCESS ) {
switch_channel_event_set_data ( channel , event ) ;
2012-12-20 17:44:21 +00:00
if ( ! strncasecmp ( file , " local_stream: " , 13 ) ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Playback-File-Type " , " local_stream " ) ;
}
if ( ! strncasecmp ( file , " tone_stream: " , 12 ) ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Playback-File-Type " , " tone_stream " ) ;
}
2011-02-25 16:55:33 +00:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Playback-File-Path " , file ) ;
2013-02-20 22:34:13 +00:00
if ( fh - > params ) {
switch_event_merge ( event , fh - > params ) ;
}
2011-02-25 16:55:33 +00:00
switch_event_fire ( & event ) ;
}
2009-04-28 23:46:18 +00:00
for ( ; ; ) {
int do_speed = 1 ;
int last_speed = - 1 ;
2010-06-04 15:15:04 +00:00
int f ;
2013-11-27 00:38:30 +00:00
2009-04-28 23:46:18 +00:00
if ( ! switch_channel_ready ( channel ) ) {
status = SWITCH_STATUS_FALSE ;
2010-02-06 03:38:24 +00:00
break ;
2009-04-28 23:46:18 +00:00
}
2007-03-29 22:34:40 +00:00
2010-06-04 15:15:04 +00:00
if ( ( f = switch_channel_test_flag ( channel , CF_BREAK ) ) ) {
2009-04-28 23:46:18 +00:00
switch_channel_clear_flag ( channel , CF_BREAK ) ;
2010-06-04 15:15:04 +00:00
if ( f = = 2 ) {
done = 1 ;
}
2009-04-28 23:46:18 +00:00
status = SWITCH_STATUS_BREAK ;
2010-02-06 03:38:24 +00:00
break ;
2009-04-28 23:46:18 +00:00
}
2007-03-29 22:34:40 +00:00
2009-10-12 22:23:55 +00:00
switch_ivr_parse_all_events ( session ) ;
2007-03-29 22:34:40 +00:00
2011-01-24 20:04:26 +00:00
if ( args ) {
2009-04-28 23:46:18 +00:00
/*
2013-11-27 00:38:30 +00:00
dtmf handler function you can hook up to be executed when a digit is dialed during playback
2010-02-06 03:38:24 +00:00
if you return anything but SWITCH_STATUS_SUCCESS the playback will stop .
*/
2009-04-28 23:46:18 +00:00
if ( switch_channel_has_dtmf ( channel ) ) {
2010-10-11 23:38:30 +00:00
if ( ! args - > input_callback & & ! args - > buf & & ! args - > dmachine ) {
2009-04-28 23:46:18 +00:00
status = SWITCH_STATUS_BREAK ;
done = 1 ;
2010-02-06 03:38:24 +00:00
break ;
2009-04-28 23:46:18 +00:00
}
switch_channel_dequeue_dtmf ( channel , & dtmf ) ;
2010-10-04 23:23:43 +00:00
if ( args - > dmachine ) {
char ds [ 2 ] = { dtmf . digit , ' \0 ' } ;
if ( ( status = switch_ivr_dmachine_feed ( args - > dmachine , ds , NULL ) ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
2013-11-27 00:38:30 +00:00
}
2012-01-05 15:39:18 +00:00
if ( args - > input_callback ) {
2009-04-28 23:46:18 +00:00
status = args - > input_callback ( session , ( void * ) & dtmf , SWITCH_INPUT_TYPE_DTMF , args - > buf , args - > buflen ) ;
2012-01-05 22:01:27 +00:00
} else if ( args - > buf ) {
2009-04-28 23:46:18 +00:00
* ( ( char * ) args - > buf ) = dtmf . digit ;
status = SWITCH_STATUS_BREAK ;
}
}
2007-07-03 02:10:35 +00:00
2009-04-28 23:46:18 +00:00
if ( args - > input_callback ) {
switch_event_t * event ;
2007-06-25 21:25:33 +00:00
2009-04-28 23:46:18 +00:00
if ( switch_core_session_dequeue_event ( session , & event , SWITCH_FALSE ) = = SWITCH_STATUS_SUCCESS ) {
2013-07-01 19:31:43 +00:00
switch_status_t ostatus = args - > input_callback ( session , event , SWITCH_INPUT_TYPE_EVENT , args - > buf , args - > buflen ) ;
if ( ostatus ! = SWITCH_STATUS_SUCCESS ) {
status = ostatus ;
}
2014-04-19 17:29:00 +00:00
2009-04-28 23:46:18 +00:00
switch_event_destroy ( & event ) ;
}
}
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
if ( status ! = SWITCH_STATUS_SUCCESS ) {
2007-03-29 22:34:40 +00:00
done = 1 ;
2010-02-06 03:38:24 +00:00
break ;
2007-03-29 22:34:40 +00:00
}
}
2014-06-12 17:06:33 +00:00
buflen = FILE_STARTSAMPLES * sizeof ( * abuf ) * fh - > cur_channels ? fh - > cur_channels : fh - > channels ;
2013-09-20 18:34:57 +00:00
if ( buflen > write_frame . buflen ) {
abuf = realloc ( abuf , buflen ) ;
write_frame . data = abuf ;
write_frame . buflen = buflen ;
}
2009-04-28 23:46:18 +00:00
if ( switch_test_flag ( fh , SWITCH_FILE_PAUSE ) ) {
if ( framelen > FILE_STARTSAMPLES ) {
framelen = FILE_STARTSAMPLES ;
}
2010-10-11 21:36:04 +00:00
memset ( abuf , 255 , framelen ) ;
2009-04-28 23:46:18 +00:00
olen = ilen ;
do_speed = 0 ;
} else if ( fh - > sp_audio_buffer & & ( eof | | ( switch_buffer_inuse ( fh - > sp_audio_buffer ) > ( switch_size_t ) ( framelen ) ) ) ) {
if ( ! ( bread = switch_buffer_read ( fh - > sp_audio_buffer , abuf , framelen ) ) ) {
if ( eof ) {
continue ;
} else {
2010-02-06 03:38:24 +00:00
break ;
2009-04-28 23:46:18 +00:00
}
2007-03-29 22:34:40 +00:00
}
2009-04-28 23:46:18 +00:00
if ( bread < framelen ) {
2010-10-11 21:36:04 +00:00
memset ( abuf + bread , 255 , framelen - bread ) ;
2009-04-28 23:46:18 +00:00
}
2007-03-29 22:34:40 +00:00
2011-03-31 20:01:58 +00:00
olen = switch_test_flag ( fh , SWITCH_FILE_NATIVE ) ? framelen : ilen ;
2009-04-28 23:46:18 +00:00
do_speed = 0 ;
} else if ( fh - > audio_buffer & & ( eof | | ( switch_buffer_inuse ( fh - > audio_buffer ) > ( switch_size_t ) ( framelen ) ) ) ) {
if ( ! ( bread = switch_buffer_read ( fh - > audio_buffer , abuf , framelen ) ) ) {
if ( eof ) {
2010-02-06 03:38:24 +00:00
break ;
2009-04-28 23:46:18 +00:00
} else {
continue ;
}
2008-07-23 23:24:18 +00:00
}
2014-01-22 21:28:53 +00:00
fh - > offset_pos + = ( uint32_t ) ( switch_test_flag ( fh , SWITCH_FILE_NATIVE ) ? bread : bread / 2 ) ;
2010-10-17 23:52:03 +00:00
2009-04-28 23:46:18 +00:00
if ( bread < framelen ) {
2010-10-11 21:36:04 +00:00
memset ( abuf + bread , 255 , framelen - bread ) ;
2009-04-28 23:46:18 +00:00
}
2008-07-23 23:24:18 +00:00
2011-03-31 20:01:58 +00:00
olen = switch_test_flag ( fh , SWITCH_FILE_NATIVE ) ? framelen : ilen ;
2009-04-28 23:46:18 +00:00
} else {
2013-09-20 18:34:57 +00:00
switch_status_t rstatus ;
2008-07-23 23:24:18 +00:00
if ( eof ) {
2009-04-28 23:46:18 +00:00
break ;
}
olen = FILE_STARTSAMPLES ;
2011-03-31 20:01:58 +00:00
if ( ! switch_test_flag ( fh , SWITCH_FILE_NATIVE ) ) {
2009-04-28 23:46:18 +00:00
olen / = 2 ;
}
2013-09-20 18:34:57 +00:00
switch_set_flag ( fh , SWITCH_FILE_BREAK_ON_CHANGE ) ;
2015-03-03 00:05:59 +00:00
2013-09-20 18:34:57 +00:00
if ( ( rstatus = switch_core_file_read ( fh , abuf , & olen ) ) = = SWITCH_STATUS_BREAK ) {
continue ;
}
2014-06-12 17:06:33 +00:00
2013-09-20 18:34:57 +00:00
if ( rstatus ! = SWITCH_STATUS_SUCCESS ) {
2009-04-28 23:46:18 +00:00
eof + + ;
2008-07-23 23:24:18 +00:00
continue ;
}
2013-11-27 00:38:30 +00:00
2011-03-31 20:01:58 +00:00
test_native = switch_test_flag ( fh , SWITCH_FILE_NATIVE ) ;
if ( test_native ! = last_native ) {
if ( test_native ) {
write_frame . codec = switch_core_session_get_read_codec ( session ) ;
samples = read_impl . samples_per_packet ;
2013-11-27 00:38:30 +00:00
framelen = read_impl . encoded_bytes_per_packet ;
2014-10-09 21:53:38 +00:00
if ( framelen = = 0 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " %s cannot play or record native files with variable length data \n " , switch_channel_get_name ( channel ) ) ;
eof + + ;
continue ;
}
2011-03-31 20:01:58 +00:00
} else {
write_frame . codec = & codec ;
samples = codec . implementation - > samples_per_packet ;
framelen = codec . implementation - > decoded_bytes_per_packet ;
}
switch_buffer_zero ( fh - > audio_buffer ) ;
}
last_native = test_native ;
2014-06-12 17:06:33 +00:00
switch_buffer_write ( fh - > audio_buffer , abuf , switch_test_flag ( fh , SWITCH_FILE_NATIVE ) ? olen : olen * 2 * fh - > channels ) ;
2009-04-28 23:46:18 +00:00
olen = switch_buffer_read ( fh - > audio_buffer , abuf , framelen ) ;
2014-01-22 21:28:53 +00:00
fh - > offset_pos + = ( uint32_t ) ( olen / 2 ) ;
2010-10-17 23:52:03 +00:00
2011-03-31 20:01:58 +00:00
if ( ! switch_test_flag ( fh , SWITCH_FILE_NATIVE ) ) {
2009-04-28 23:46:18 +00:00
olen / = 2 ;
}
2010-10-17 23:52:03 +00:00
2008-07-23 22:10:48 +00:00
}
2008-07-23 23:24:18 +00:00
2009-04-28 23:46:18 +00:00
if ( done | | olen < = 0 ) {
2010-02-06 03:38:24 +00:00
break ;
2008-07-23 23:24:18 +00:00
}
2011-03-31 20:01:58 +00:00
if ( ! switch_test_flag ( fh , SWITCH_FILE_NATIVE ) ) {
2009-04-28 23:46:18 +00:00
if ( fh - > speed > 2 ) {
fh - > speed = 2 ;
} else if ( fh - > speed < - 2 ) {
fh - > speed = - 2 ;
}
2007-03-29 22:34:40 +00:00
}
2011-03-31 20:01:58 +00:00
if ( ! switch_test_flag ( fh , SWITCH_FILE_NATIVE ) & & fh - > audio_buffer & & last_speed > - 1 & & last_speed ! = fh - > speed ) {
2009-04-28 23:46:18 +00:00
switch_buffer_zero ( fh - > sp_audio_buffer ) ;
2007-03-29 22:34:40 +00:00
}
2009-04-28 23:46:18 +00:00
if ( switch_test_flag ( fh , SWITCH_FILE_SEEK ) ) {
/* file position has changed flush the buffer */
switch_buffer_zero ( fh - > audio_buffer ) ;
switch_clear_flag ( fh , SWITCH_FILE_SEEK ) ;
}
2007-03-29 22:34:40 +00:00
2008-03-07 22:40:20 +00:00
2011-03-31 20:01:58 +00:00
if ( ! switch_test_flag ( fh , SWITCH_FILE_NATIVE ) & & fh - > speed & & do_speed ) {
2009-04-28 23:46:18 +00:00
float factor = 0.25f * abs ( fh - > speed ) ;
switch_size_t newlen , supplement , step ;
short * bp = write_frame . data ;
switch_size_t wrote = 0 ;
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
supplement = ( int ) ( factor * olen ) ;
if ( ! supplement ) {
supplement = 1 ;
}
newlen = ( fh - > speed > 0 ) ? olen - supplement : olen + supplement ;
2008-05-27 04:30:03 +00:00
2009-04-28 23:46:18 +00:00
step = ( fh - > speed > 0 ) ? ( newlen / supplement ) : ( olen / supplement ) ;
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
if ( ! fh - > sp_audio_buffer ) {
switch_buffer_create_dynamic ( & fh - > sp_audio_buffer , 1024 , 1024 , 0 ) ;
}
2008-03-07 22:40:20 +00:00
2009-04-28 23:46:18 +00:00
while ( ( wrote + step ) < newlen ) {
switch_buffer_write ( fh - > sp_audio_buffer , bp , step * 2 ) ;
wrote + = step ;
bp + = step ;
if ( fh - > speed > 0 ) {
bp + + ;
} else {
float f ;
short s ;
f = ( float ) ( * bp + * ( bp + 1 ) + * ( bp - 1 ) ) ;
f / = 3 ;
s = ( short ) f ;
switch_buffer_write ( fh - > sp_audio_buffer , & s , 2 ) ;
wrote + + ;
}
}
if ( wrote < newlen ) {
switch_size_t r = newlen - wrote ;
switch_buffer_write ( fh - > sp_audio_buffer , bp , r * 2 ) ;
wrote + = r ;
2007-03-29 22:34:40 +00:00
}
2009-04-28 23:46:18 +00:00
last_speed = fh - > speed ;
continue ;
2007-03-29 22:34:40 +00:00
}
2013-11-27 00:38:30 +00:00
2009-04-28 23:46:18 +00:00
if ( olen < llen ) {
uint8_t * dp = ( uint8_t * ) write_frame . data ;
2010-10-11 21:36:04 +00:00
memset ( dp + ( int ) olen , 255 , ( int ) ( llen - olen ) ) ;
2009-04-28 23:46:18 +00:00
olen = llen ;
2007-03-29 22:34:40 +00:00
}
2010-07-29 22:41:23 +00:00
if ( ! more_data ) {
if ( timer_name ) {
if ( switch_core_timer_next ( & timer ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
} else { /* time off the channel (if you must) */
switch_frame_t * read_frame ;
switch_status_t tstatus ;
2013-11-27 00:38:30 +00:00
2010-07-29 22:41:23 +00:00
while ( switch_channel_ready ( channel ) & & switch_channel_test_flag ( channel , CF_HOLD ) ) {
2012-04-18 19:49:00 +00:00
switch_ivr_parse_all_messages ( session ) ;
2010-07-29 22:41:23 +00:00
switch_yield ( 10000 ) ;
}
tstatus = switch_core_session_read_frame ( session , & read_frame , SWITCH_IO_FLAG_SINGLE_READ , 0 ) ;
2012-12-22 05:56:53 +00:00
2010-07-29 22:41:23 +00:00
if ( ! SWITCH_READ_ACCEPTABLE ( tstatus ) ) {
break ;
}
2010-10-04 23:23:43 +00:00
if ( args & & args - > dmachine ) {
if ( ( status = switch_ivr_dmachine_ping ( args - > dmachine , NULL ) ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
}
2010-07-29 22:41:23 +00:00
if ( args & & ( args - > read_frame_callback ) ) {
int ok = 1 ;
switch_set_flag ( fh , SWITCH_FILE_CALLBACK ) ;
2010-10-04 23:23:43 +00:00
if ( ( status = args - > read_frame_callback ( session , read_frame , args - > user_data ) ) ! = SWITCH_STATUS_SUCCESS ) {
2010-07-29 22:41:23 +00:00
ok = 0 ;
}
switch_clear_flag ( fh , SWITCH_FILE_CALLBACK ) ;
if ( ! ok ) {
break ;
}
}
}
}
more_data = 0 ;
2009-04-28 23:46:18 +00:00
write_frame . samples = ( uint32_t ) olen ;
2007-07-05 17:03:14 +00:00
2011-03-31 20:01:58 +00:00
if ( switch_test_flag ( fh , SWITCH_FILE_NATIVE ) ) {
2009-04-28 23:46:18 +00:00
write_frame . datalen = ( uint32_t ) olen ;
} else {
write_frame . datalen = write_frame . samples * 2 ;
}
2007-07-05 17:03:14 +00:00
2009-04-28 23:46:18 +00:00
llen = olen ;
2007-03-29 22:34:40 +00:00
2009-04-28 23:46:18 +00:00
if ( timer_name ) {
write_frame . timestamp = timer . samplecount ;
}
2007-03-29 22:34:40 +00:00
# ifndef WIN32
2008-09-24 19:36:24 +00:00
# if SWITCH_BYTE_ORDER == __BIG_ENDIAN
2011-03-31 20:01:58 +00:00
if ( ! switch_test_flag ( fh , SWITCH_FILE_NATIVE ) & & l16 ) {
2009-04-28 23:46:18 +00:00
switch_swap_linear ( write_frame . data , ( int ) write_frame . datalen / 2 ) ;
}
2008-09-24 19:36:24 +00:00
# endif
2007-03-29 22:34:40 +00:00
# endif
2011-03-31 20:01:58 +00:00
if ( ! switch_test_flag ( fh , SWITCH_FILE_NATIVE ) & & fh - > vol ) {
2009-04-28 23:46:18 +00:00
switch_change_sln_volume ( write_frame . data , write_frame . datalen / 2 , fh - > vol ) ;
}
2007-03-29 22:34:40 +00:00
2014-08-05 20:21:34 +00:00
/* write silence while dmachine is in reading state */
if ( args & & args - > dmachine & & switch_ivr_dmachine_is_parsing ( args - > dmachine ) ) {
memset ( write_frame . data , 0 , write_frame . datalen ) ;
}
2009-04-28 23:46:18 +00:00
status = switch_core_session_write_frame ( session , & write_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2008-05-27 04:30:03 +00:00
2010-06-18 23:07:31 +00:00
if ( timeout_samples ) {
timeout_samples - = write_frame . samples ;
if ( timeout_samples < = 0 ) {
timeout_samples = 0 ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " timeout reached playing file \n " ) ;
2013-01-13 06:18:44 +00:00
if ( timeout_as_success ) {
status = SWITCH_STATUS_SUCCESS ;
} else {
status = SWITCH_STATUS_TIMEOUT ;
}
2010-06-18 23:07:31 +00:00
break ;
}
}
2013-11-27 00:38:30 +00:00
2010-06-18 23:07:31 +00:00
2009-04-28 23:46:18 +00:00
if ( status = = SWITCH_STATUS_MORE_DATA ) {
status = SWITCH_STATUS_SUCCESS ;
2010-07-29 22:41:23 +00:00
more_data = 1 ;
2009-04-28 23:46:18 +00:00
continue ;
} else if ( status ! = SWITCH_STATUS_SUCCESS ) {
done = 1 ;
2010-02-06 03:38:24 +00:00
break ;
2007-03-29 22:34:40 +00:00
}
2008-05-27 04:30:03 +00:00
2009-04-28 23:46:18 +00:00
if ( done ) {
2010-02-06 03:38:24 +00:00
break ;
2007-03-29 22:34:40 +00:00
}
}
2011-10-26 17:57:54 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " done playing file %s \n " , file ) ;
2013-11-25 22:09:12 +00:00
switch_channel_set_variable_printf ( channel , " playback_last_offset_pos " , " %d " , fh - > offset_pos ) ;
2010-02-06 03:38:24 +00:00
2009-10-13 22:29:20 +00:00
if ( read_impl . samples_per_second ) {
2013-05-21 15:03:22 +00:00
switch_channel_set_variable_printf ( channel , " playback_seconds " , " %d " , fh - > samples_in / fh - > native_rate ) ;
2013-07-10 14:43:33 +00:00
switch_channel_set_variable_printf ( channel , " playback_ms " , " %d " , fh - > samples_in / ( fh - > native_rate / 1000 ) ) ;
2009-10-13 22:29:20 +00:00
}
2010-12-13 16:30:00 +00:00
switch_channel_set_variable_printf ( channel , " playback_samples " , " %d " , fh - > samples_in ) ;
2008-05-27 04:30:03 +00:00
2011-02-25 16:55:33 +00:00
if ( switch_event_create ( & event , SWITCH_EVENT_PLAYBACK_STOP ) = = SWITCH_STATUS_SUCCESS ) {
switch_channel_event_set_data ( channel , event ) ;
2012-12-20 17:44:21 +00:00
if ( ! strncasecmp ( file , " local_stream: " , 13 ) ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Playback-File-Type " , " local_stream " ) ;
}
if ( ! strncasecmp ( file , " tone_stream: " , 12 ) ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Playback-File-Type " , " tone_stream " ) ;
}
2011-02-25 16:55:33 +00:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Playback-File-Path " , file ) ;
if ( status = = SWITCH_STATUS_BREAK ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Playback-Status " , " break " ) ;
} else {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Playback-Status " , " done " ) ;
}
2013-02-20 22:34:13 +00:00
if ( fh - > params ) {
switch_event_merge ( event , fh - > params ) ;
}
2011-02-25 16:55:33 +00:00
switch_event_fire ( & event ) ;
}
2010-11-30 21:34:22 +00:00
switch_core_session_io_write_lock ( session ) ;
switch_channel_set_private ( channel , " __fh " , NULL ) ;
switch_core_session_io_rwunlock ( session ) ;
2015-02-27 05:51:04 +00:00
if ( switch_core_file_has_video ( fh ) ) {
2015-03-27 20:59:51 +00:00
//switch_channel_clear_flag_recursive(channel, CF_VIDEO_DECODED_READ);
2015-02-27 19:55:54 +00:00
switch_core_media_set_video_file ( session , NULL , SWITCH_RW_WRITE ) ;
2015-02-27 05:51:04 +00:00
}
2009-04-28 23:46:18 +00:00
switch_core_file_close ( fh ) ;
2009-04-21 19:32:55 +00:00
2009-04-28 23:46:18 +00:00
if ( fh - > audio_buffer ) {
switch_buffer_destroy ( & fh - > audio_buffer ) ;
}
2010-02-06 03:38:24 +00:00
2009-04-28 23:46:18 +00:00
if ( fh - > sp_audio_buffer ) {
switch_buffer_destroy ( & fh - > sp_audio_buffer ) ;
}
}
2009-04-21 19:32:55 +00:00
2009-04-28 23:46:18 +00:00
if ( switch_core_codec_ready ( ( & codec ) ) ) {
2007-03-29 22:34:40 +00:00
switch_core_codec_destroy ( & codec ) ;
}
2009-04-28 23:46:18 +00:00
if ( timer . samplecount ) {
2007-03-29 22:34:40 +00:00
/* End the audio absorbing thread */
2008-10-23 23:48:11 +00:00
switch_core_thread_session_end ( session ) ;
2007-03-29 22:34:40 +00:00
switch_core_timer_destroy ( & timer ) ;
}
2008-05-19 19:57:27 +00:00
switch_safe_free ( abuf ) ;
2007-12-18 17:33:29 +00:00
2009-12-18 23:19:53 +00:00
switch_core_session_reset ( session , SWITCH_FALSE , SWITCH_FALSE ) ;
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2007-03-29 22:34:40 +00:00
return status ;
}
2008-07-10 19:59:57 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_wait_for_silence ( switch_core_session_t * session , uint32_t thresh ,
uint32_t silence_hits , uint32_t listen_hits , uint32_t timeout_ms , const char * file )
2008-07-10 15:57:41 +00:00
{
uint32_t score , count = 0 , j = 0 ;
double energy = 0 ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
int divisor = 0 ;
uint32_t org_silence_hits = silence_hits ;
uint32_t channels ;
switch_frame_t * read_frame ;
switch_status_t status = SWITCH_STATUS_FALSE ;
int16_t * data ;
2008-07-11 13:01:27 +00:00
uint32_t listening = 0 ;
2008-07-10 15:57:41 +00:00
int countdown = 0 ;
2010-02-06 03:38:24 +00:00
switch_codec_t raw_codec = { 0 } ;
2008-07-10 15:57:41 +00:00
int16_t * abuf = NULL ;
2010-02-06 03:38:24 +00:00
switch_frame_t write_frame = { 0 } ;
switch_file_handle_t fh = { 0 } ;
2008-07-10 19:59:57 +00:00
int32_t sample_count = 0 ;
2010-02-06 03:38:24 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
switch_core_session_get_read_impl ( session , & read_impl ) ;
2008-07-10 15:57:41 +00:00
2008-07-10 19:59:57 +00:00
if ( timeout_ms ) {
2009-02-10 19:09:06 +00:00
sample_count = ( read_impl . actual_samples_per_second / 1000 ) * timeout_ms ;
2008-07-10 19:59:57 +00:00
}
2008-07-10 15:57:41 +00:00
if ( file ) {
if ( switch_core_file_open ( & fh ,
file ,
2009-02-10 19:09:06 +00:00
read_impl . number_of_channels ,
2010-02-06 03:38:24 +00:00
read_impl . actual_samples_per_second , SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT , NULL ) ! = SWITCH_STATUS_SUCCESS ) {
2009-12-18 23:19:53 +00:00
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_FALSE ) ;
2008-07-10 15:57:41 +00:00
return SWITCH_STATUS_NOTFOUND ;
}
switch_zmalloc ( abuf , SWITCH_RECOMMENDED_BUFFER_SIZE ) ;
write_frame . data = abuf ;
write_frame . buflen = SWITCH_RECOMMENDED_BUFFER_SIZE ;
}
if ( switch_core_codec_init ( & raw_codec ,
" L16 " ,
NULL ,
2015-03-19 19:26:47 +00:00
NULL ,
2009-02-10 19:09:06 +00:00
read_impl . actual_samples_per_second ,
read_impl . microseconds_per_packet / 1000 ,
2008-07-10 15:57:41 +00:00
1 , SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE ,
NULL , switch_core_session_get_pool ( session ) ) ! = SWITCH_STATUS_SUCCESS ) {
status = SWITCH_STATUS_FALSE ;
goto end ;
}
write_frame . codec = & raw_codec ;
2009-02-10 19:09:06 +00:00
divisor = read_impl . actual_samples_per_second / 8000 ;
channels = read_impl . number_of_channels ;
2008-07-10 15:57:41 +00:00
switch_core_session_set_read_codec ( session , & raw_codec ) ;
while ( switch_channel_ready ( channel ) ) {
status = switch_core_session_read_frame ( session , & read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2010-02-06 03:38:24 +00:00
2008-07-10 15:57:41 +00:00
if ( ! SWITCH_READ_ACCEPTABLE ( status ) ) {
break ;
}
2008-07-10 19:59:57 +00:00
if ( sample_count ) {
2008-10-20 17:48:42 +00:00
sample_count - = raw_codec . implementation - > samples_per_packet ;
2008-07-10 19:59:57 +00:00
if ( sample_count < = 0 ) {
2013-11-27 00:38:30 +00:00
switch_channel_set_variable ( channel , " wait_for_silence_timeout " , " true " ) ;
switch_channel_set_variable_printf ( channel , " wait_for_silence_listenhits " , " %d " , listening ) ;
switch_channel_set_variable_printf ( channel , " wait_for_silence_silence_hits " , " %d " , silence_hits ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " switch_ivr_wait_for_silence: TIMEOUT %d \n " , countdown ) ;
2008-07-10 19:59:57 +00:00
break ;
}
}
2013-11-27 00:38:30 +00:00
2008-07-10 15:57:41 +00:00
if ( abuf ) {
2008-10-20 17:48:42 +00:00
switch_size_t olen = raw_codec . implementation - > samples_per_packet ;
2013-11-27 00:38:30 +00:00
2008-07-10 15:57:41 +00:00
if ( switch_core_file_read ( & fh , abuf , & olen ) ! = SWITCH_STATUS_SUCCESS ) {
2010-02-06 03:38:24 +00:00
break ;
}
2013-11-27 00:38:30 +00:00
2010-02-06 03:38:24 +00:00
write_frame . samples = ( uint32_t ) olen ;
2014-06-13 00:13:43 +00:00
write_frame . datalen = ( uint32_t ) ( olen * sizeof ( int16_t ) * fh . channels ) ;
2008-07-10 15:57:41 +00:00
if ( ( status = switch_core_session_write_frame ( session , & write_frame , SWITCH_IO_FLAG_NONE , 0 ) ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
}
2013-11-27 00:38:30 +00:00
2008-07-10 15:57:41 +00:00
if ( countdown ) {
if ( ! - - countdown ) {
2013-11-27 00:38:30 +00:00
switch_channel_set_variable ( channel , " wait_for_silence_timeout " , " false " ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " switch_ivr_wait_for_silence: SILENCE DETECTED \n " ) ;
2008-07-10 15:57:41 +00:00
break ;
} else {
continue ;
}
}
data = ( int16_t * ) read_frame - > data ;
2010-02-06 03:38:24 +00:00
2008-07-10 15:57:41 +00:00
for ( energy = 0 , j = 0 , count = 0 ; count < read_frame - > samples ; count + + ) {
energy + = abs ( data [ j + + ] ) ;
j + = channels ;
}
2010-02-06 03:38:24 +00:00
2008-07-10 15:57:41 +00:00
score = ( uint32_t ) ( energy / ( read_frame - > samples / divisor ) ) ;
2010-02-06 03:38:24 +00:00
2008-07-10 15:57:41 +00:00
if ( score > = thresh ) {
listening + + ;
}
if ( listening > listen_hits & & score < thresh ) {
if ( ! - - silence_hits ) {
countdown = 25 ;
}
} else {
silence_hits = org_silence_hits ;
}
}
2009-01-09 20:34:01 +00:00
switch_core_session_reset ( session , SWITCH_FALSE , SWITCH_TRUE ) ;
2008-07-10 15:57:41 +00:00
switch_core_codec_destroy ( & raw_codec ) ;
2010-02-06 03:38:24 +00:00
end :
2008-07-10 15:57:41 +00:00
if ( abuf ) {
switch_core_file_close ( & fh ) ;
2008-09-04 22:43:49 +00:00
free ( abuf ) ;
2008-07-10 15:57:41 +00:00
}
return status ;
}
2008-03-04 18:55:16 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_read ( switch_core_session_t * session ,
uint32_t min_digits ,
uint32_t max_digits ,
const char * prompt_audio_file ,
const char * var_name ,
2013-11-27 00:38:30 +00:00
char * digit_buffer ,
switch_size_t digit_buffer_length ,
uint32_t timeout ,
2010-09-23 23:37:45 +00:00
const char * valid_terminators ,
uint32_t digit_timeout )
2008-03-04 18:55:16 +00:00
{
switch_channel_t * channel ;
switch_input_args_t args = { 0 } ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2009-03-05 03:08:15 +00:00
size_t len = 0 ;
2009-03-30 16:48:44 +00:00
char tb [ 2 ] = " " ;
2012-06-28 18:17:52 +00:00
int term_required = 0 ;
2013-11-27 00:38:30 +00:00
2012-06-28 18:17:52 +00:00
2012-07-02 15:55:49 +00:00
if ( valid_terminators & & * valid_terminators = = ' = ' ) {
2012-06-28 18:17:52 +00:00
term_required = 1 ;
}
2008-03-04 18:55:16 +00:00
switch_assert ( session ) ;
2010-12-13 23:59:32 +00:00
if ( ! digit_timeout ) {
digit_timeout = timeout ;
}
2008-11-14 14:20:10 +00:00
if ( max_digits < min_digits ) {
2010-02-06 03:38:24 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING ,
2008-11-14 14:20:10 +00:00
" Max digits %u is less than Min %u, forcing Max to %u \n " , max_digits , min_digits , min_digits ) ;
max_digits = min_digits ;
}
2008-03-04 18:55:16 +00:00
channel = switch_core_session_get_channel ( session ) ;
2008-08-05 21:50:48 +00:00
switch_channel_set_variable ( channel , SWITCH_READ_RESULT_VARIABLE , NULL ) ;
2008-03-04 18:55:16 +00:00
2009-12-11 21:50:29 +00:00
if ( var_name ) {
switch_channel_set_variable ( channel , var_name , NULL ) ;
}
2008-09-08 22:34:28 +00:00
if ( ( min_digits & & digit_buffer_length < min_digits ) | | digit_buffer_length < max_digits ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Buffer too small! \n " ) ;
2008-03-04 18:55:16 +00:00
return SWITCH_STATUS_FALSE ;
}
2009-02-10 19:09:06 +00:00
if ( switch_channel_pre_answer ( channel ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_FALSE ;
}
2008-03-04 18:55:16 +00:00
memset ( digit_buffer , 0 , digit_buffer_length ) ;
args . buf = digit_buffer ;
2008-05-27 04:30:03 +00:00
args . buflen = ( uint32_t ) digit_buffer_length ;
2008-03-04 18:55:16 +00:00
2009-10-23 16:03:42 +00:00
if ( ! zstr ( prompt_audio_file ) & & strcasecmp ( prompt_audio_file , " silence " ) ) {
2008-11-14 14:20:10 +00:00
if ( ( status = switch_ivr_play_file ( session , NULL , prompt_audio_file , & args ) ) = = SWITCH_STATUS_BREAK ) {
status = SWITCH_STATUS_SUCCESS ;
}
2008-03-04 18:55:16 +00:00
}
2008-05-27 04:30:03 +00:00
2008-03-04 18:55:16 +00:00
if ( status ! = SWITCH_STATUS_SUCCESS & & status ! = SWITCH_STATUS_BREAK ) {
goto end ;
}
len = strlen ( digit_buffer ) ;
2008-05-27 04:30:03 +00:00
2008-09-08 22:34:28 +00:00
if ( ( min_digits & & len < min_digits ) | | len < max_digits ) {
2008-03-04 18:55:16 +00:00
args . buf = digit_buffer + len ;
2008-05-27 04:30:03 +00:00
args . buflen = ( uint32_t ) ( digit_buffer_length - len ) ;
2013-11-27 00:38:30 +00:00
status = switch_ivr_collect_digits_count ( session , digit_buffer , digit_buffer_length , max_digits , valid_terminators , & tb [ 0 ] ,
2010-09-23 23:37:45 +00:00
len ? digit_timeout : timeout , digit_timeout , 0 ) ;
2009-03-30 16:48:44 +00:00
}
if ( tb [ 0 ] ) {
2011-05-19 20:39:03 +00:00
char * p ;
2009-03-30 16:48:44 +00:00
switch_channel_set_variable ( channel , SWITCH_READ_TERMINATOR_USED_VARIABLE , tb ) ;
2011-05-19 20:39:03 +00:00
2013-12-26 18:57:10 +00:00
if ( ! zstr ( valid_terminators ) & & ( p = strchr ( valid_terminators , tb [ 0 ] ) ) ) {
2011-05-19 20:39:03 +00:00
if ( p > = ( valid_terminators + 1 ) & & ( * ( p - 1 ) = = ' + ' | | * ( p - 1 ) = = ' x ' ) ) {
switch_snprintf ( digit_buffer + strlen ( digit_buffer ) , digit_buffer_length - strlen ( digit_buffer ) , " %s " , tb ) ;
if ( * ( p - 1 ) = = ' x ' ) {
status = SWITCH_STATUS_RESTART ;
}
}
}
2012-06-28 18:17:52 +00:00
} else if ( term_required ) {
status = SWITCH_STATUS_TOO_SMALL ;
2008-03-04 18:55:16 +00:00
}
2008-11-13 20:23:59 +00:00
len = strlen ( digit_buffer ) ;
if ( ( min_digits & & len < min_digits ) ) {
status = SWITCH_STATUS_TOO_SMALL ;
}
2008-11-14 14:20:10 +00:00
switch ( status ) {
case SWITCH_STATUS_SUCCESS :
2008-08-05 21:50:48 +00:00
switch_channel_set_variable ( channel , SWITCH_READ_RESULT_VARIABLE , " success " ) ;
2008-11-14 14:20:10 +00:00
break ;
case SWITCH_STATUS_TIMEOUT :
2008-08-05 21:50:48 +00:00
switch_channel_set_variable ( channel , SWITCH_READ_RESULT_VARIABLE , " timeout " ) ;
2008-11-14 14:20:10 +00:00
break ;
default :
2008-08-05 21:50:48 +00:00
switch_channel_set_variable ( channel , SWITCH_READ_RESULT_VARIABLE , " failure " ) ;
2008-11-14 14:20:10 +00:00
break ;
2010-02-06 03:38:24 +00:00
2008-08-05 21:50:48 +00:00
}
2010-02-06 03:38:24 +00:00
end :
2008-03-04 18:55:16 +00:00
2011-05-19 20:39:03 +00:00
if ( status ! = SWITCH_STATUS_RESTART & & max_digits = = 1 & & len = = 1 & & valid_terminators & & strchr ( valid_terminators , * digit_buffer ) ) {
2009-03-05 03:08:15 +00:00
* digit_buffer = ' \0 ' ;
}
2009-10-23 16:03:42 +00:00
if ( var_name & & ! zstr ( digit_buffer ) ) {
2008-03-04 18:55:16 +00:00
switch_channel_set_variable ( channel , var_name , digit_buffer ) ;
}
return status ;
2008-05-27 04:30:03 +00:00
2008-03-04 18:55:16 +00:00
}
2007-03-29 22:34:40 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_play_and_get_digits ( switch_core_session_t * session ,
uint32_t min_digits ,
uint32_t max_digits ,
uint32_t max_tries ,
uint32_t timeout ,
2009-01-14 20:29:16 +00:00
const char * valid_terminators ,
const char * prompt_audio_file ,
2010-02-06 03:38:24 +00:00
const char * bad_input_audio_file ,
2009-01-15 03:42:45 +00:00
const char * var_name ,
2013-11-27 00:38:30 +00:00
char * digit_buffer ,
uint32_t digit_buffer_length ,
2010-09-23 23:37:45 +00:00
const char * digits_regex ,
2011-08-19 03:29:52 +00:00
uint32_t digit_timeout ,
const char * transfer_on_failure )
2007-03-29 22:34:40 +00:00
{
2008-11-13 20:23:59 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2007-03-29 22:34:40 +00:00
2010-02-06 03:38:24 +00:00
while ( switch_channel_ready ( channel ) & & max_tries ) {
2008-11-13 20:23:59 +00:00
switch_status_t status ;
2010-02-06 03:38:24 +00:00
2007-03-29 22:34:40 +00:00
memset ( digit_buffer , 0 , digit_buffer_length ) ;
2011-01-24 20:04:26 +00:00
2010-02-06 03:38:24 +00:00
status = switch_ivr_read ( session , min_digits , max_digits , prompt_audio_file , var_name ,
2010-09-23 23:37:45 +00:00
digit_buffer , digit_buffer_length , timeout , valid_terminators , digit_timeout ) ;
2011-05-19 20:39:03 +00:00
if ( status = = SWITCH_STATUS_RESTART ) {
return status ;
}
2008-11-14 02:59:00 +00:00
if ( status = = SWITCH_STATUS_TIMEOUT & & strlen ( digit_buffer ) > = min_digits ) {
status = SWITCH_STATUS_SUCCESS ;
}
2010-12-22 04:15:03 +00:00
if ( ( min_digits = = 0 ) & & ( strlen ( digit_buffer ) = = 0 ) & & switch_channel_get_variable ( channel , SWITCH_READ_TERMINATOR_USED_VARIABLE ) ! = 0 )
{
return SWITCH_STATUS_SUCCESS ;
}
2010-02-19 18:59:10 +00:00
if ( ! ( status = = SWITCH_STATUS_TOO_SMALL & & strlen ( digit_buffer ) = = 0 ) ) {
if ( status = = SWITCH_STATUS_SUCCESS ) {
if ( ! zstr ( digit_buffer ) ) {
2015-07-06 21:13:12 +00:00
char * invalid_var = NULL ;
2010-02-19 18:59:10 +00:00
if ( zstr ( digits_regex ) ) {
return SWITCH_STATUS_SUCCESS ;
}
2013-02-26 17:49:17 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG1 , " Test Regex [%s][%s] \n " , digit_buffer , digits_regex ) ;
2015-07-06 21:13:12 +00:00
invalid_var = switch_mprintf ( " %s_invalid " , var_name ) ;
2010-02-19 18:59:10 +00:00
if ( switch_regex_match ( digit_buffer , digits_regex ) = = SWITCH_STATUS_SUCCESS ) {
2015-07-06 21:13:12 +00:00
switch_channel_set_variable ( channel , invalid_var , NULL ) ;
switch_safe_free ( invalid_var ) ;
2010-02-19 18:59:10 +00:00
return SWITCH_STATUS_SUCCESS ;
} else {
switch_channel_set_variable ( channel , var_name , NULL ) ;
2015-07-06 21:13:12 +00:00
switch_channel_set_variable ( channel , invalid_var , digit_buffer ) ;
switch_safe_free ( invalid_var ) ;
2010-02-19 18:59:10 +00:00
}
2007-03-29 22:34:40 +00:00
}
}
}
2008-11-13 20:23:59 +00:00
if ( ! switch_channel_ready ( channel ) ) {
break ;
2007-03-29 22:34:40 +00:00
}
2008-11-13 20:23:59 +00:00
switch_ivr_play_file ( session , NULL , bad_input_audio_file , NULL ) ;
max_tries - - ;
2007-03-29 22:34:40 +00:00
}
2008-11-14 14:20:10 +00:00
memset ( digit_buffer , 0 , digit_buffer_length ) ;
2013-11-27 00:38:30 +00:00
2011-08-19 03:29:52 +00:00
/* If we get here then check for transfer-on-failure ext/dp/context */
/* split this arg on spaces to get ext, dp, and context */
2013-11-27 00:38:30 +00:00
2011-08-19 03:29:52 +00:00
if ( ! zstr ( transfer_on_failure ) ) {
const char * failure_ext = NULL ;
const char * failure_dialplan = NULL ;
const char * failure_context = NULL ;
char * target [ 4 ] ;
char * mydata = switch_core_session_strdup ( session , transfer_on_failure ) ;
int argc ;
2013-11-27 00:38:30 +00:00
2011-08-19 03:29:52 +00:00
argc = switch_separate_string ( mydata , ' ' , target , ( sizeof ( target ) / sizeof ( target [ 0 ] ) ) ) ;
2013-11-27 00:38:30 +00:00
2011-08-19 03:29:52 +00:00
if ( argc < 1 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Bad target for PAGD failure: [%s] \n " , transfer_on_failure ) ;
return SWITCH_STATUS_FALSE ;
}
2013-11-27 00:38:30 +00:00
2011-08-19 03:29:52 +00:00
if ( argc > 0 ) {
failure_ext = target [ 0 ] ;
}
2013-11-27 00:38:30 +00:00
2011-08-19 03:29:52 +00:00
if ( argc > 1 ) {
failure_dialplan = target [ 1 ] ;
}
if ( argc > 2 ) {
failure_context = target [ 2 ] ;
}
2013-11-27 00:38:30 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING ,
2011-08-19 03:29:52 +00:00
" PAGD failure! Transfer to: %s / %s / %s \n " , failure_ext , failure_dialplan , failure_context ) ;
2013-11-27 00:38:30 +00:00
2011-08-19 03:29:52 +00:00
switch_ivr_session_transfer ( session , failure_ext , failure_dialplan , failure_context ) ;
return SWITCH_STATUS_FALSE ;
2013-11-27 00:38:30 +00:00
}
return SWITCH_STATUS_FALSE ;
2007-03-29 22:34:40 +00:00
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_speak_text_handle ( switch_core_session_t * session ,
switch_speech_handle_t * sh ,
2007-03-30 00:13:31 +00:00
switch_codec_t * codec , switch_timer_t * timer , char * text , switch_input_args_t * args )
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 ) ;
2014-06-12 17:06:33 +00:00
short abuf [ SWITCH_RECOMMENDED_BUFFER_SIZE ] ;
2008-05-27 04:30:03 +00:00
switch_dtmf_t dtmf = { 0 } ;
2007-03-29 22:34:40 +00:00
uint32_t len = 0 ;
switch_size_t ilen = 0 ;
switch_frame_t write_frame = { 0 } ;
int done = 0 ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE ;
2007-10-17 20:14:19 +00:00
switch_size_t extra = 0 ;
2007-10-16 16:49:44 +00:00
char * p , * tmp = NULL ;
2007-11-01 11:28:26 +00:00
const char * star , * pound ;
2007-10-16 18:49:56 +00:00
switch_size_t starlen , poundlen ;
2007-03-29 22:34:40 +00:00
if ( ! sh ) {
return SWITCH_STATUS_FALSE ;
}
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
2013-03-30 03:35:32 +00:00
if ( ! switch_core_codec_ready ( codec ) ) {
return SWITCH_STATUS_FALSE ;
}
2012-12-10 16:56:07 +00:00
arg_recursion_check_start ( args ) ;
2007-03-29 22:34:40 +00:00
write_frame . data = abuf ;
write_frame . buflen = sizeof ( abuf ) ;
2014-06-12 17:06:33 +00:00
len = sh - > samples * 2 * sh - > channels ;
2008-05-27 04:30:03 +00:00
2007-03-29 22:34:40 +00:00
flags = 0 ;
2008-05-27 04:30:03 +00:00
2007-10-16 18:49:56 +00:00
if ( ! ( star = switch_channel_get_variable ( channel , " star_replace " ) ) ) {
star = " star " ;
}
if ( ! ( pound = switch_channel_get_variable ( channel , " pound_replace " ) ) ) {
pound = " pound " ;
}
starlen = strlen ( star ) ;
poundlen = strlen ( pound ) ;
2008-05-27 04:30:03 +00:00
for ( p = text ; p & & * p ; p + + ) {
2007-10-16 16:49:44 +00:00
if ( * p = = ' * ' ) {
2007-10-16 18:49:56 +00:00
extra + = starlen ;
2007-10-16 16:49:44 +00:00
} else if ( * p = = ' # ' ) {
2007-10-16 18:49:56 +00:00
extra + = poundlen ;
2007-10-16 16:49:44 +00:00
}
}
if ( extra ) {
char * tp ;
switch_size_t mylen = strlen ( text ) + extra + 1 ;
tmp = malloc ( mylen ) ;
2008-05-21 20:25:40 +00:00
if ( ! tmp ) {
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2008-05-21 20:25:40 +00:00
return SWITCH_STATUS_MEMERR ;
}
2007-10-16 18:49:56 +00:00
memset ( tmp , 0 , mylen ) ;
2007-10-16 16:49:44 +00:00
tp = tmp ;
for ( p = text ; p & & * p ; p + + ) {
if ( * p = = ' * ' ) {
2007-10-16 18:49:56 +00:00
strncat ( tp , star , starlen ) ;
tp + = starlen ;
2008-05-27 04:30:03 +00:00
} else if ( * p = = ' # ' ) {
2007-10-16 18:49:56 +00:00
strncat ( tp , pound , poundlen ) ;
tp + = poundlen ;
2007-10-16 16:49:44 +00:00
} else {
* tp + + = * p ;
}
}
2008-05-27 04:30:03 +00:00
2007-10-16 16:49:44 +00:00
text = tmp ;
}
2007-03-29 22:34:40 +00:00
switch_core_speech_feed_tts ( sh , text , & flags ) ;
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Speaking text: %s \n " , text ) ;
2007-10-16 16:49:44 +00:00
switch_safe_free ( tmp ) ;
text = NULL ;
2007-03-29 22:34:40 +00:00
write_frame . rate = sh - > rate ;
memset ( write_frame . data , 0 , len ) ;
write_frame . datalen = len ;
write_frame . samples = len / 2 ;
write_frame . codec = codec ;
2007-12-11 19:23:57 +00:00
switch_assert ( codec - > implementation ! = NULL ) ;
2007-07-02 20:16:08 +00:00
2012-04-05 18:15:45 +00:00
switch_channel_audio_sync ( channel ) ;
2014-06-12 17:06:33 +00:00
2008-05-27 04:30:03 +00:00
for ( ; ; ) {
2007-03-29 22:34:40 +00:00
switch_event_t * event ;
2014-06-12 17:06:33 +00:00
ilen = len ;
2007-07-03 02:10:35 +00:00
if ( ! switch_channel_ready ( channel ) ) {
2008-05-27 04:30:03 +00:00
status = SWITCH_STATUS_FALSE ;
break ;
}
2007-07-03 02:10:35 +00:00
2007-06-25 21:25:33 +00:00
if ( switch_channel_test_flag ( channel , CF_BREAK ) ) {
switch_channel_clear_flag ( channel , CF_BREAK ) ;
2007-07-03 02:10:35 +00:00
status = SWITCH_STATUS_BREAK ;
2007-06-25 21:25:33 +00:00
break ;
}
2007-03-29 22:34:40 +00:00
if ( switch_core_session_dequeue_private_event ( session , & event ) = = SWITCH_STATUS_SUCCESS ) {
switch_ivr_parse_event ( session , event ) ;
switch_event_destroy ( & event ) ;
}
2011-01-24 20:04:26 +00:00
if ( args ) {
2013-11-27 00:38:30 +00:00
/* dtmf handler function you can hook up to be executed when a digit is dialed during playback
2008-09-02 10:39:39 +00:00
* if you return anything but SWITCH_STATUS_SUCCESS the playback will stop .
2007-03-29 22:34:40 +00:00
*/
if ( switch_channel_has_dtmf ( channel ) ) {
2010-10-11 23:38:30 +00:00
if ( ! args - > input_callback & & ! args - > buf & & ! args - > dmachine ) {
2007-03-29 22:34:40 +00:00
status = SWITCH_STATUS_BREAK ;
done = 1 ;
break ;
}
if ( args - > buf & & ! strcasecmp ( args - > buf , " _break_ " ) ) {
status = SWITCH_STATUS_BREAK ;
} else {
2007-12-22 00:32:20 +00:00
switch_channel_dequeue_dtmf ( channel , & dtmf ) ;
2010-10-04 23:23:43 +00:00
if ( args - > dmachine ) {
char ds [ 2 ] = { dtmf . digit , ' \0 ' } ;
if ( ( status = switch_ivr_dmachine_feed ( args - > dmachine , ds , NULL ) ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
2013-11-27 00:38:30 +00:00
}
2012-01-05 15:39:18 +00:00
if ( args - > input_callback ) {
2007-12-22 00:32:20 +00:00
status = args - > input_callback ( session , ( void * ) & dtmf , SWITCH_INPUT_TYPE_DTMF , args - > buf , args - > buflen ) ;
2012-01-05 22:01:27 +00:00
} else if ( args - > buf ) {
2010-08-23 20:54:23 +00:00
* ( ( char * ) args - > buf ) = dtmf . digit ;
2007-03-29 22:34:40 +00:00
status = SWITCH_STATUS_BREAK ;
}
}
}
if ( args - > input_callback ) {
2009-02-21 23:19:58 +00:00
if ( switch_core_session_dequeue_event ( session , & event , SWITCH_FALSE ) = = SWITCH_STATUS_SUCCESS ) {
2013-07-01 19:31:43 +00:00
switch_status_t ostatus = args - > input_callback ( session , event , SWITCH_INPUT_TYPE_EVENT , args - > buf , args - > buflen ) ;
if ( ostatus ! = SWITCH_STATUS_SUCCESS ) {
status = ostatus ;
}
2007-03-29 22:34:40 +00:00
switch_event_destroy ( & event ) ;
}
}
if ( status ! = SWITCH_STATUS_SUCCESS ) {
done = 1 ;
break ;
}
}
if ( switch_test_flag ( sh , SWITCH_SPEECH_FLAG_PAUSE ) ) {
if ( timer ) {
if ( switch_core_timer_next ( timer ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
} else {
switch_frame_t * read_frame ;
2008-05-08 19:19:47 +00:00
switch_status_t tstatus = switch_core_session_read_frame ( session , & read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2007-03-29 22:34:40 +00:00
while ( switch_channel_ready ( channel ) & & switch_channel_test_flag ( channel , CF_HOLD ) ) {
2012-04-18 19:49:00 +00:00
switch_ivr_parse_all_messages ( session ) ;
2007-03-29 22:34:40 +00:00
switch_yield ( 10000 ) ;
}
2007-12-18 17:50:39 +00:00
if ( ! SWITCH_READ_ACCEPTABLE ( tstatus ) ) {
2007-03-29 22:34:40 +00:00
break ;
}
2007-10-02 00:09:49 +00:00
2010-10-04 23:23:43 +00:00
if ( args & & args - > dmachine ) {
if ( ( status = switch_ivr_dmachine_ping ( args - > dmachine , NULL ) ) ! = SWITCH_STATUS_SUCCESS ) {
goto done ;
}
}
2007-10-02 00:09:49 +00:00
if ( args & & ( args - > read_frame_callback ) ) {
2010-10-04 23:23:43 +00:00
if ( ( status = args - > read_frame_callback ( session , read_frame , args - > user_data ) ) ! = SWITCH_STATUS_SUCCESS ) {
goto done ;
2007-10-02 00:09:49 +00:00
}
}
2007-03-29 22:34:40 +00:00
}
continue ;
}
2014-06-12 17:06:33 +00:00
2007-03-29 22:34:40 +00:00
flags = SWITCH_SPEECH_FLAG_BLOCKING ;
2009-02-18 18:53:28 +00:00
status = switch_core_speech_read_tts ( sh , abuf , & ilen , & flags ) ;
2007-03-29 22:34:40 +00:00
if ( status ! = SWITCH_STATUS_SUCCESS ) {
if ( status = = SWITCH_STATUS_BREAK ) {
status = SWITCH_STATUS_SUCCESS ;
}
done = 1 ;
}
if ( done ) {
break ;
}
write_frame . datalen = ( uint32_t ) ilen ;
2014-06-12 17:06:33 +00:00
write_frame . samples = ( uint32_t ) ( ilen / 2 / sh - > channels ) ;
2007-03-29 22:34:40 +00:00
if ( timer ) {
write_frame . timestamp = timer - > samplecount ;
}
2008-05-08 19:19:47 +00:00
if ( switch_core_session_write_frame ( session , & write_frame , SWITCH_IO_FLAG_NONE , 0 ) ! = SWITCH_STATUS_SUCCESS ) {
2007-03-29 22:34:40 +00:00
done = 1 ;
break ;
}
if ( done ) {
break ;
}
if ( timer ) {
if ( switch_core_timer_next ( timer ) ! = SWITCH_STATUS_SUCCESS ) {
break ;
}
} else { /* time off the channel (if you must) */
switch_frame_t * read_frame ;
2008-05-08 19:19:47 +00:00
switch_status_t tstatus = switch_core_session_read_frame ( session , & read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2007-03-29 22:34:40 +00:00
while ( switch_channel_ready ( channel ) & & switch_channel_test_flag ( channel , CF_HOLD ) ) {
2012-04-18 19:49:00 +00:00
switch_ivr_parse_all_messages ( session ) ;
2007-03-29 22:34:40 +00:00
switch_yield ( 10000 ) ;
}
2007-12-18 17:50:39 +00:00
if ( ! SWITCH_READ_ACCEPTABLE ( tstatus ) ) {
2007-03-29 22:34:40 +00:00
break ;
}
2007-10-02 00:09:49 +00:00
2010-10-04 23:23:43 +00:00
if ( args & & args - > dmachine ) {
if ( ( status = switch_ivr_dmachine_ping ( args - > dmachine , NULL ) ) ! = SWITCH_STATUS_SUCCESS ) {
goto done ;
}
}
2007-10-02 00:09:49 +00:00
if ( args & & ( args - > read_frame_callback ) ) {
2010-10-04 23:23:43 +00:00
if ( ( status = args - > read_frame_callback ( session , read_frame , args - > user_data ) ) ! = SWITCH_STATUS_SUCCESS ) {
goto done ;
2007-10-02 00:09:49 +00:00
}
}
2007-03-29 22:34:40 +00:00
}
}
2010-10-04 23:23:43 +00:00
done :
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " done speaking text \n " ) ;
2007-03-29 22:34:40 +00:00
flags = 0 ;
switch_core_speech_flush_tts ( sh ) ;
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2007-03-29 22:34:40 +00:00
return status ;
}
2007-10-15 16:25:08 +00:00
struct cached_speech_handle {
char tts_name [ 80 ] ;
char voice_name [ 80 ] ;
switch_speech_handle_t sh ;
switch_codec_t codec ;
switch_timer_t timer ;
} ;
2008-09-02 10:39:39 +00:00
2007-10-15 16:25:08 +00:00
typedef struct cached_speech_handle cached_speech_handle_t ;
2008-05-27 04:30:03 +00:00
SWITCH_DECLARE ( void ) switch_ivr_clear_speech_cache ( switch_core_session_t * session )
2007-10-15 16:25:08 +00:00
{
cached_speech_handle_t * cache_obj = NULL ;
2008-01-28 07:26:10 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2007-10-15 16:25:08 +00:00
if ( ( cache_obj = switch_channel_get_private ( channel , SWITCH_CACHE_SPEECH_HANDLES_OBJ_NAME ) ) ) {
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE ;
if ( cache_obj - > timer . interval ) {
switch_core_timer_destroy ( & cache_obj - > timer ) ;
}
2015-02-17 17:20:24 +00:00
if ( cache_obj - > sh . speech_interface ) {
2012-04-05 18:15:45 +00:00
switch_core_speech_close ( & cache_obj - > sh , & flags ) ;
}
2015-02-17 17:20:24 +00:00
switch_core_codec_destroy ( & cache_obj - > codec ) ;
2007-10-15 16:25:08 +00:00
switch_channel_set_private ( channel , SWITCH_CACHE_SPEECH_HANDLES_OBJ_NAME , NULL ) ;
}
}
2007-03-29 22:34:40 +00:00
SWITCH_DECLARE ( switch_status_t ) switch_ivr_speak_text ( switch_core_session_t * session ,
2007-11-01 11:28:26 +00:00
const char * tts_name , const char * voice_name , char * text , switch_input_args_t * args )
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-08-28 17:06:20 +00:00
uint32_t rate = 0 ;
2007-03-29 22:34:40 +00:00
int interval = 0 ;
2014-06-12 17:06:33 +00:00
uint32_t channels ;
2007-03-29 22:34:40 +00:00
switch_frame_t write_frame = { 0 } ;
2007-10-15 16:25:08 +00:00
switch_timer_t ltimer , * timer ;
switch_codec_t lcodec , * codec ;
2007-03-29 22:34:40 +00:00
switch_memory_pool_t * pool = switch_core_session_get_pool ( session ) ;
char * codec_name ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2007-10-15 16:25:08 +00:00
switch_speech_handle_t lsh , * sh ;
2007-03-29 22:34:40 +00:00
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE ;
2007-11-01 11:28:26 +00:00
const char * timer_name , * var ;
2007-10-15 16:25:08 +00:00
cached_speech_handle_t * cache_obj = NULL ;
int need_create = 1 , need_alloc = 1 ;
2010-02-06 03:38:24 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
switch_core_session_get_read_impl ( session , & read_impl ) ;
2007-03-29 22:34:40 +00:00
2009-02-10 19:09:06 +00:00
if ( switch_channel_pre_answer ( channel ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_FALSE ;
}
2008-01-07 21:47:32 +00:00
2012-12-10 16:56:07 +00:00
arg_recursion_check_start ( args ) ;
2007-10-15 16:25:08 +00:00
sh = & lsh ;
codec = & lcodec ;
timer = & ltimer ;
if ( ( var = switch_channel_get_variable ( channel , SWITCH_CACHE_SPEECH_HANDLES_VARIABLE ) ) & & switch_true ( var ) ) {
2012-04-05 18:15:45 +00:00
if ( ( cache_obj = ( cached_speech_handle_t * ) switch_channel_get_private ( channel , SWITCH_CACHE_SPEECH_HANDLES_OBJ_NAME ) ) ) {
2007-10-15 16:25:08 +00:00
need_create = 0 ;
if ( ! strcasecmp ( cache_obj - > tts_name , tts_name ) ) {
need_alloc = 0 ;
} else {
switch_ivr_clear_speech_cache ( session ) ;
}
}
if ( ! cache_obj ) {
2012-04-05 18:15:45 +00:00
cache_obj = ( cached_speech_handle_t * ) switch_core_session_alloc ( session , sizeof ( * cache_obj ) ) ;
2007-10-15 16:25:08 +00:00
}
if ( need_alloc ) {
switch_copy_string ( cache_obj - > tts_name , tts_name , sizeof ( cache_obj - > tts_name ) ) ;
switch_copy_string ( cache_obj - > voice_name , voice_name , sizeof ( cache_obj - > voice_name ) ) ;
switch_channel_set_private ( channel , SWITCH_CACHE_SPEECH_HANDLES_OBJ_NAME , cache_obj ) ;
}
sh = & cache_obj - > sh ;
codec = & cache_obj - > codec ;
timer = & cache_obj - > timer ;
}
2007-03-29 22:34:40 +00:00
timer_name = switch_channel_get_variable ( channel , " timer_name " ) ;
2009-12-18 23:19:53 +00:00
switch_core_session_reset ( session , SWITCH_FALSE , SWITCH_FALSE ) ;
2008-05-27 04:30:03 +00:00
2009-02-10 19:09:06 +00:00
rate = read_impl . actual_samples_per_second ;
interval = read_impl . microseconds_per_packet / 1000 ;
2014-06-12 17:06:33 +00:00
channels = read_impl . number_of_channels ;
2008-05-27 04:30:03 +00:00
2007-10-15 16:25:08 +00:00
if ( need_create ) {
memset ( sh , 0 , sizeof ( * sh ) ) ;
2014-06-12 17:06:33 +00:00
if ( ( status = switch_core_speech_open ( sh , tts_name , voice_name , ( uint32_t ) rate , interval , read_impl . number_of_channels , & flags , NULL ) ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Invalid TTS module! \n " ) ;
2009-01-09 20:34:01 +00:00
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_TRUE ) ;
2010-03-05 18:58:08 +00:00
switch_ivr_clear_speech_cache ( session ) ;
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2009-11-23 17:54:08 +00:00
return status ;
2007-10-15 16:25:08 +00:00
}
} else if ( cache_obj & & strcasecmp ( cache_obj - > voice_name , voice_name ) ) {
switch_copy_string ( cache_obj - > voice_name , voice_name , sizeof ( cache_obj - > voice_name ) ) ;
switch_core_speech_text_param_tts ( sh , " voice " , voice_name ) ;
2007-03-29 22:34:40 +00:00
}
2009-02-10 19:09:06 +00:00
if ( switch_channel_pre_answer ( channel ) ! = SWITCH_STATUS_SUCCESS ) {
2010-03-05 18:58:08 +00:00
flags = 0 ;
switch_core_speech_close ( sh , & flags ) ;
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2009-02-10 19:09:06 +00:00
return SWITCH_STATUS_FALSE ;
}
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " OPEN TTS %s \n " , tts_name ) ;
2007-03-29 22:34:40 +00:00
codec_name = " L16 " ;
2014-06-12 17:06:33 +00:00
2007-10-15 16:25:08 +00:00
if ( need_create ) {
if ( switch_core_codec_init ( codec ,
codec_name ,
2015-03-19 19:26:47 +00:00
NULL ,
2014-06-12 17:06:33 +00:00
NULL , ( int ) rate , interval , channels , SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE , NULL ,
2008-05-27 04:30:03 +00:00
pool ) = = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Raw Codec Activated \n " ) ;
2007-10-15 16:25:08 +00:00
} else {
2010-02-06 03:38:24 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Raw Codec Activation Failed %s@%uhz 1 channel %dms \n " , codec_name ,
rate , interval ) ;
2007-03-29 22:34:40 +00:00
flags = 0 ;
2007-10-15 16:25:08 +00:00
switch_core_speech_close ( sh , & flags ) ;
2009-01-09 20:34:01 +00:00
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_TRUE ) ;
2010-03-05 18:58:08 +00:00
switch_ivr_clear_speech_cache ( session ) ;
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2007-03-29 22:34:40 +00:00
return SWITCH_STATUS_GENERR ;
}
2007-10-15 16:25:08 +00:00
}
2008-05-27 04:30:03 +00:00
2007-10-15 16:25:08 +00:00
write_frame . codec = codec ;
2007-03-29 22:34:40 +00:00
2007-10-15 16:25:08 +00:00
if ( timer_name ) {
if ( need_create ) {
if ( switch_core_timer_init ( timer , timer_name , interval , ( int ) sh - > samples , pool ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Setup timer failed! \n " ) ;
2007-10-15 16:25:08 +00:00
switch_core_codec_destroy ( write_frame . codec ) ;
flags = 0 ;
switch_core_speech_close ( sh , & flags ) ;
2009-01-09 20:34:01 +00:00
switch_core_session_reset ( session , SWITCH_TRUE , SWITCH_TRUE ) ;
2010-03-05 18:58:08 +00:00
switch_ivr_clear_speech_cache ( session ) ;
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2007-10-15 16:25:08 +00:00
return SWITCH_STATUS_GENERR ;
}
2010-02-06 03:38:24 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Setup timer success %u bytes per %d ms! \n " , sh - > samples * 2 ,
interval ) ;
2007-10-15 16:25:08 +00:00
}
2010-07-29 22:41:23 +00:00
switch_core_timer_sync ( timer ) ; // Sync timer
2007-03-29 22:34:40 +00:00
/* start a thread to absorb incoming audio */
2008-10-23 23:48:11 +00:00
switch_core_service_session ( session ) ;
2008-05-08 19:19:47 +00:00
2007-03-29 22:34:40 +00:00
}
2008-05-27 04:30:03 +00:00
2007-10-15 16:25:08 +00:00
status = switch_ivr_speak_text_handle ( session , sh , write_frame . codec , timer_name ? timer : NULL , text , args ) ;
2007-03-29 22:34:40 +00:00
flags = 0 ;
2007-10-15 16:25:08 +00:00
if ( ! cache_obj ) {
switch_core_speech_close ( sh , & flags ) ;
switch_core_codec_destroy ( codec ) ;
}
2007-03-29 22:34:40 +00:00
if ( timer_name ) {
/* End the audio absorbing thread */
2008-10-23 23:48:11 +00:00
switch_core_thread_session_end ( session ) ;
2007-10-15 16:25:08 +00:00
if ( ! cache_obj ) {
switch_core_timer_destroy ( timer ) ;
}
2007-03-29 22:34:40 +00:00
}
2009-01-09 20:34:01 +00:00
switch_core_session_reset ( session , SWITCH_FALSE , SWITCH_TRUE ) ;
2012-12-10 16:56:07 +00:00
arg_recursion_check_stop ( args ) ;
2007-03-29 22:34:40 +00:00
return status ;
}
2008-01-27 05:02:52 +00:00
2008-04-09 18:15:15 +00:00
static switch_status_t hold_on_dtmf ( switch_core_session_t * session , void * input , switch_input_type_t itype , void * buf , unsigned int buflen )
{
char * stop_key = ( char * ) buf ;
switch ( itype ) {
case SWITCH_INPUT_TYPE_DTMF :
2008-05-27 04:30:03 +00:00
{
switch_dtmf_t * dtmf = ( switch_dtmf_t * ) input ;
2008-04-09 18:15:15 +00:00
if ( dtmf - > digit = = * stop_key ) {
return SWITCH_STATUS_BREAK ;
}
}
break ;
default :
break ;
}
return SWITCH_STATUS_SUCCESS ;
}
SWITCH_DECLARE ( switch_status_t ) switch_ivr_soft_hold ( switch_core_session_t * session , const char * unhold_key , const char * moh_a , const char * moh_b )
{
switch_channel_t * channel , * other_channel ;
switch_core_session_t * other_session ;
const char * other_uuid , * moh = NULL ;
int moh_br = 0 ;
switch_input_args_t args = { 0 } ;
args . input_callback = hold_on_dtmf ;
args . buf = ( void * ) unhold_key ;
2008-05-27 04:30:03 +00:00
args . buflen = ( uint32_t ) strlen ( unhold_key ) ;
2008-04-09 18:15:15 +00:00
switch_assert ( session ! = NULL ) ;
channel = switch_core_session_get_channel ( session ) ;
switch_assert ( channel ! = NULL ) ;
2012-05-29 18:10:15 +00:00
if ( ( other_uuid = switch_channel_get_partner_uuid ( channel ) ) ) {
2008-04-09 18:15:15 +00:00
if ( ( other_session = switch_core_session_locate ( other_uuid ) ) ) {
other_channel = switch_core_session_get_channel ( other_session ) ;
if ( moh_b ) {
2008-05-27 04:30:03 +00:00
moh = moh_b ;
2008-04-09 18:15:15 +00:00
} else {
2011-01-06 00:58:56 +00:00
moh = switch_channel_get_hold_music ( other_channel ) ;
2008-04-09 18:15:15 +00:00
}
2009-10-23 16:03:42 +00:00
if ( ! zstr ( moh ) & & strcasecmp ( moh , " silence " ) & & ! switch_channel_test_flag ( other_channel , CF_BROADCAST ) ) {
2008-04-09 18:15:15 +00:00
switch_ivr_broadcast ( other_uuid , moh , SMF_ECHO_ALEG | SMF_LOOP ) ;
moh_br + + ;
}
2008-05-27 04:30:03 +00:00
2008-04-09 18:15:15 +00:00
if ( moh_a ) {
moh = moh_a ;
} else {
2011-01-06 00:58:56 +00:00
moh = switch_channel_get_hold_music ( channel ) ;
2008-04-09 18:15:15 +00:00
}
2008-05-27 04:30:03 +00:00
2009-10-23 16:03:42 +00:00
if ( ! zstr ( moh ) & & strcasecmp ( moh , " silence " ) ) {
2008-04-09 18:15:15 +00:00
switch_ivr_play_file ( session , NULL , moh , & args ) ;
} else {
2009-09-25 19:07:20 +00:00
switch_ivr_collect_digits_callback ( session , & args , 0 , 0 ) ;
2008-05-27 04:30:03 +00:00
}
2008-04-09 18:15:15 +00:00
if ( moh_br ) {
switch_channel_stop_broadcast ( other_channel ) ;
}
switch_core_session_rwunlock ( other_session ) ;
return SWITCH_STATUS_SUCCESS ;
}
2008-05-27 04:30:03 +00:00
2008-04-09 18:15:15 +00:00
}
2008-05-27 04:30:03 +00:00
2009-08-13 20:35:02 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " Channel %s is not in a bridge \n " , switch_channel_get_name ( channel ) ) ;
2008-04-09 18:15:15 +00:00
return SWITCH_STATUS_FALSE ;
}
2008-01-27 05:02:52 +00:00
/* For Emacs:
* Local Variables :
* mode : c
2008-02-03 22:14:57 +00:00
* indent - tabs - mode : t
2008-01-27 05:02:52 +00:00
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
2013-06-25 16:50:17 +00:00
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 noet :
2008-01-27 05:02:52 +00:00
*/