2008-02-09 00:37:58 +00:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
2012-04-18 11:51:48 -05:00
* Copyright ( C ) 2005 - 2012 , Anthony Minessale II < anthm @ freeswitch . org >
2008-02-09 00:37:58 +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 >
2008-02-09 00:37:58 +00:00
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
*
2009-02-04 21:20:54 +00:00
* Anthony Minessale II < anthm @ freeswitch . org >
2012-07-20 08:43:05 +08:00
* Seven Du < dujinfang @ gmail . com >
2008-02-09 00:37:58 +00:00
*
* mod_fsv - - FS Video File Format
*
2012-07-20 08:43:05 +08:00
*
2008-02-09 00:37:58 +00:00
*/
2012-07-20 08:43:05 +08:00
2008-02-09 00:37:58 +00:00
# include <switch.h>
SWITCH_MODULE_LOAD_FUNCTION ( mod_fsv_load ) ;
SWITCH_MODULE_DEFINITION ( mod_fsv , mod_fsv_load , NULL , NULL ) ;
# define VID_BIT (1 << 31)
# define VERSION 4201
struct file_header {
int32_t version ;
char video_codec_name [ 32 ] ;
char video_fmtp [ 128 ] ;
uint32_t audio_rate ;
uint32_t audio_ptime ;
switch_time_t created ;
} ;
struct record_helper {
switch_core_session_t * session ;
switch_mutex_t * mutex ;
int fd ;
int up ;
2011-05-27 19:14:00 -05:00
switch_size_t shared_ts ;
2008-02-09 00:37:58 +00:00
} ;
static void * SWITCH_THREAD_FUNC record_video_thread ( switch_thread_t * thread , void * obj )
{
struct record_helper * eh = obj ;
switch_core_session_t * session = eh - > session ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
switch_status_t status ;
switch_frame_t * read_frame ;
int bytes ;
2008-05-27 04:54:52 +00:00
eh - > up = 1 ;
2011-05-27 19:14:00 -05:00
while ( switch_channel_ready ( channel ) & & eh - > up ) {
2008-05-08 19:19:47 +00:00
status = switch_core_session_read_video_frame ( session , & read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2008-02-09 00:37:58 +00:00
if ( ! SWITCH_READ_ACCEPTABLE ( status ) ) {
break ;
}
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
if ( switch_test_flag ( read_frame , SFF_CNG ) ) {
continue ;
}
2008-05-27 04:54:52 +00:00
bytes = read_frame - > packetlen | VID_BIT ;
2008-02-09 00:37:58 +00:00
switch_mutex_lock ( eh - > mutex ) ;
2008-05-27 04:54:52 +00:00
if ( write ( eh - > fd , & bytes , sizeof ( bytes ) ) ! = ( int ) sizeof ( bytes ) ) {
2008-02-09 00:37:58 +00:00
switch_mutex_unlock ( eh - > mutex ) ;
break ;
}
2008-05-27 04:54:52 +00:00
if ( write ( eh - > fd , read_frame - > packet , read_frame - > packetlen ) ! = ( int ) read_frame - > packetlen ) {
2008-02-09 00:37:58 +00:00
switch_mutex_unlock ( eh - > mutex ) ;
break ;
}
switch_mutex_unlock ( eh - > mutex ) ;
2008-05-27 04:54:52 +00:00
2008-05-08 19:19:47 +00:00
switch_core_session_write_video_frame ( session , read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2008-02-09 00:37:58 +00:00
}
eh - > up = 0 ;
return NULL ;
}
SWITCH_STANDARD_APP ( record_fsv_function )
{
switch_status_t status ;
switch_frame_t * read_frame ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2008-05-27 04:54:52 +00:00
struct record_helper eh = { 0 } ;
2008-02-09 00:37:58 +00:00
switch_thread_t * thread ;
switch_threadattr_t * thd_attr = NULL ;
int fd ;
switch_mutex_t * mutex = NULL ;
2009-02-10 19:09:06 +00:00
switch_codec_t codec , * vid_codec ;
2010-02-06 03:38:24 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
2011-05-27 19:14:00 -05:00
switch_dtmf_t dtmf = { 0 } ;
2010-03-25 19:08:00 +00:00
int count = 0 , sanity = 30 ;
2012-01-18 14:08:55 -06:00
switch_core_session_message_t msg = { 0 } ;
/* Tell the channel to request a fresh vid frame */
msg . from = __FILE__ ;
msg . message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ ;
2008-05-27 04:54:52 +00:00
2010-03-25 19:06:18 +00:00
switch_core_session_get_read_impl ( session , & read_impl ) ;
2008-02-09 00:37:58 +00:00
switch_channel_answer ( channel ) ;
2012-01-18 14:08:55 -06:00
switch_core_session_receive_message ( session , & msg ) ;
2008-05-27 04:54:52 +00:00
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_PLAYBACK_TERMINATOR_USED , " " ) ;
2010-03-25 19:06:18 +00:00
while ( switch_channel_up ( channel ) & & ! switch_channel_test_flag ( channel , CF_VIDEO ) ) {
switch_yield ( 10000 ) ;
if ( count ) count - - ;
if ( count = = 0 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_INFO , " %s waiting for video. \n " , switch_channel_get_name ( channel ) ) ;
count = 100 ;
2010-03-25 19:08:00 +00:00
if ( ! - - sanity ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " %s timeout waiting for video. \n " ,
switch_channel_get_name ( channel ) ) ;
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " Got timeout while waiting for video " ) ;
2010-03-25 19:08:00 +00:00
return ;
}
2010-03-25 19:06:18 +00:00
}
}
if ( ! switch_channel_ready ( channel ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " %s not ready. \n " , switch_channel_get_name ( channel ) ) ;
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " Channel not ready " ) ;
2010-03-25 19:06:18 +00:00
return ;
}
2008-11-19 17:08:46 +00:00
if ( ( fd = open ( ( char * ) data , O_WRONLY | O_CREAT | O_TRUNC | O_BINARY , S_IRUSR | S_IWUSR ) ) < 0 ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " Error opening file %s \n " , ( char * ) data ) ;
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " Got error while opening file " ) ;
2008-02-09 00:37:58 +00:00
return ;
}
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
if ( switch_core_codec_init ( & codec ,
" L16 " ,
NULL ,
2009-02-10 19:09:06 +00:00
read_impl . samples_per_second ,
read_impl . microseconds_per_packet / 1000 ,
2008-02-09 00:37:58 +00:00
1 , SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE ,
NULL , switch_core_session_get_pool ( session ) ) = = SWITCH_STATUS_SUCCESS ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Audio Codec Activation Success \n " ) ;
2008-02-09 00:37:58 +00:00
} else {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Audio Codec Activation Fail \n " ) ;
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " Audio codec activation failed " ) ;
2008-02-09 00:37:58 +00:00
goto end ;
}
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
switch_core_session_set_read_codec ( session , & codec ) ;
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
if ( switch_channel_test_flag ( channel , CF_VIDEO ) ) {
struct file_header h ;
memset ( & h , 0 , sizeof ( h ) ) ;
vid_codec = switch_core_session_get_video_read_codec ( session ) ;
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
h . version = VERSION ;
2009-01-25 21:23:07 +00:00
h . created = switch_micro_time_now ( ) ;
2008-02-09 00:37:58 +00:00
switch_set_string ( h . video_codec_name , vid_codec - > implementation - > iananame ) ;
2008-02-19 21:18:11 +00:00
if ( vid_codec - > fmtp_in ) {
switch_set_string ( h . video_fmtp , vid_codec - > fmtp_in ) ;
}
2009-02-10 19:09:06 +00:00
h . audio_rate = read_impl . samples_per_second ;
h . audio_ptime = read_impl . microseconds_per_packet / 1000 ;
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
if ( write ( fd , & h , sizeof ( h ) ) ! = sizeof ( h ) ) {
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " File write failed " ) ;
2008-02-09 00:37:58 +00:00
goto end ;
}
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
switch_mutex_init ( & mutex , SWITCH_MUTEX_NESTED , switch_core_session_get_pool ( session ) ) ;
eh . mutex = mutex ;
eh . fd = fd ;
eh . session = session ;
switch_threadattr_create ( & thd_attr , switch_core_session_get_pool ( session ) ) ;
switch_threadattr_detach_set ( thd_attr , 1 ) ;
switch_threadattr_stacksize_set ( thd_attr , SWITCH_THREAD_STACKSIZE ) ;
switch_thread_create ( & thread , thd_attr , record_video_thread , & eh , switch_core_session_get_pool ( session ) ) ;
}
2008-05-27 04:54:52 +00:00
while ( switch_channel_ready ( channel ) ) {
2008-02-09 00:37:58 +00:00
2011-05-27 19:14:00 -05:00
status = switch_core_session_read_frame ( session , & read_frame , SWITCH_IO_FLAG_SINGLE_READ , 0 ) ;
if ( switch_channel_test_flag ( channel , CF_BREAK ) ) {
switch_channel_clear_flag ( channel , CF_BREAK ) ;
eh . up = 0 ;
break ;
}
switch_ivr_parse_all_events ( session ) ;
//check for dtmf interrupts
if ( switch_channel_has_dtmf ( channel ) ) {
const char * terminators = switch_channel_get_variable ( channel , SWITCH_PLAYBACK_TERMINATORS_VARIABLE ) ;
switch_channel_dequeue_dtmf ( channel , & dtmf ) ;
if ( terminators & & ! strcasecmp ( terminators , " none " ) )
{
terminators = NULL ;
}
if ( terminators & & strchr ( terminators , dtmf . digit ) ) {
char sbuf [ 2 ] = { dtmf . digit , ' \0 ' } ;
switch_channel_set_variable ( channel , SWITCH_PLAYBACK_TERMINATOR_USED , sbuf ) ;
eh . up = 0 ;
break ;
}
}
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
if ( ! SWITCH_READ_ACCEPTABLE ( status ) ) {
2011-05-27 19:14:00 -05:00
eh . up = 0 ;
2008-02-09 00:37:58 +00:00
break ;
}
if ( switch_test_flag ( read_frame , SFF_CNG ) ) {
continue ;
}
if ( mutex ) {
switch_mutex_lock ( mutex ) ;
}
if ( write ( fd , & read_frame - > datalen , sizeof ( read_frame - > datalen ) ) ! = sizeof ( read_frame - > datalen ) ) {
if ( mutex ) {
switch_mutex_unlock ( mutex ) ;
}
break ;
}
2008-05-27 04:54:52 +00:00
if ( write ( fd , read_frame - > data , read_frame - > datalen ) ! = ( int ) read_frame - > datalen ) {
2008-02-09 00:37:58 +00:00
if ( mutex ) {
switch_mutex_unlock ( mutex ) ;
}
break ;
}
2011-05-27 19:14:00 -05:00
2008-02-09 00:37:58 +00:00
if ( mutex ) {
switch_mutex_unlock ( mutex ) ;
}
2011-05-27 19:14:00 -05:00
switch_core_session_write_frame ( session , read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2008-02-09 00:37:58 +00:00
}
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " OK " ) ;
2008-05-27 04:54:52 +00:00
end :
2008-02-09 00:37:58 +00:00
if ( eh . up ) {
2008-05-27 04:54:52 +00:00
while ( eh . up ) {
2008-11-14 23:31:21 +00:00
switch_cond_next ( ) ;
2008-02-09 00:37:58 +00:00
}
}
2012-07-12 14:01:19 -05:00
if ( fd > - 1 ) {
close ( fd ) ;
}
2009-02-10 19:09:06 +00:00
switch_core_session_set_read_codec ( session , NULL ) ;
2008-02-09 00:37:58 +00:00
switch_core_codec_destroy ( & codec ) ;
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
}
SWITCH_STANDARD_APP ( play_fsv_function )
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2008-05-27 04:54:52 +00:00
switch_frame_t write_frame = { 0 } , vid_frame = {
0 } ;
2008-02-09 00:37:58 +00:00
int fd = - 1 ;
2011-05-27 19:14:00 -05:00
int bytes ;
2010-01-07 16:40:38 +00:00
switch_codec_t codec = { 0 } , vid_codec = {
2008-05-27 04:54:52 +00:00
0 } , * read_vid_codec ;
2008-02-09 00:37:58 +00:00
unsigned char * aud_buffer ;
unsigned char * vid_buffer ;
struct file_header h ;
2008-05-27 04:54:52 +00:00
uint32_t ts = 0 , last = 0 ;
switch_timer_t timer = { 0 } ;
2008-02-11 17:14:14 +00:00
switch_payload_t pt = 0 ;
2011-05-27 19:14:00 -05:00
switch_dtmf_t dtmf = { 0 } ;
switch_frame_t * read_frame ;
2010-02-06 03:38:24 +00:00
switch_codec_implementation_t read_impl = { 0 } ;
2012-01-18 14:08:55 -06:00
switch_core_session_message_t msg = { 0 } ;
/* Tell the channel to request a fresh vid frame */
msg . from = __FILE__ ;
msg . message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ ;
switch_core_session_receive_message ( session , & msg ) ;
2011-05-27 19:14:00 -05:00
2010-02-06 03:38:24 +00:00
switch_core_session_get_read_impl ( session , & read_impl ) ;
2008-02-09 00:37:58 +00:00
aud_buffer = switch_core_session_alloc ( session , SWITCH_RECOMMENDED_BUFFER_SIZE ) ;
vid_buffer = switch_core_session_alloc ( session , SWITCH_RECOMMENDED_BUFFER_SIZE ) ;
2008-05-27 04:54:52 +00:00
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_PLAYBACK_TERMINATOR_USED , " " ) ;
2008-07-12 18:44:05 +00:00
if ( ( fd = open ( ( char * ) data , O_RDONLY | O_BINARY ) ) < 0 ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " Error opening file %s \n " , ( char * ) data ) ;
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " Got error while opening file " ) ;
2008-02-09 00:37:58 +00:00
return ;
}
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
if ( read ( fd , & h , sizeof ( h ) ) ! = sizeof ( h ) ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " Error reading file header \n " ) ;
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " Got error reading file header " ) ;
2008-02-09 00:37:58 +00:00
goto end ;
}
if ( h . version ! = VERSION ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " File version does not match! \n " ) ;
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " File version does not match! " ) ;
2008-02-09 00:37:58 +00:00
goto end ;
}
switch_channel_set_variable ( channel , " sip_force_video_fmtp " , h . video_fmtp ) ;
switch_channel_answer ( channel ) ;
2008-05-27 04:54:52 +00:00
2008-02-11 17:14:14 +00:00
if ( ( read_vid_codec = switch_core_session_get_video_read_codec ( session ) ) ) {
pt = read_vid_codec - > agreed_pt ;
}
2008-02-09 00:37:58 +00:00
write_frame . codec = & codec ;
write_frame . data = aud_buffer ;
write_frame . buflen = SWITCH_RECOMMENDED_BUFFER_SIZE ;
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
vid_frame . codec = & vid_codec ;
vid_frame . packet = vid_buffer ;
vid_frame . data = vid_buffer + 12 ;
vid_frame . buflen = SWITCH_RECOMMENDED_BUFFER_SIZE - 12 ;
switch_set_flag ( ( & vid_frame ) , SFF_RAW_RTP ) ;
2010-01-07 16:40:38 +00:00
switch_set_flag ( ( & vid_frame ) , SFF_PROXY_PACKET ) ;
2008-05-27 04:54:52 +00:00
2009-02-10 19:09:06 +00:00
if ( switch_core_timer_init ( & timer , " soft " , read_impl . microseconds_per_packet / 1000 ,
read_impl . samples_per_packet , switch_core_session_get_pool ( session ) ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Timer Activation Fail \n " ) ;
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " Timer activation failed! " ) ;
2008-02-09 00:37:58 +00:00
goto end ;
}
if ( switch_core_codec_init ( & codec ,
" L16 " ,
NULL ,
h . audio_rate ,
h . audio_ptime ,
1 , SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE ,
NULL , switch_core_session_get_pool ( session ) ) = = SWITCH_STATUS_SUCCESS ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Audio Codec Activation Success \n " ) ;
2008-02-09 00:37:58 +00:00
} else {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Audio Codec Activation Fail \n " ) ;
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " Audio codec activation failed " ) ;
2008-02-09 00:37:58 +00:00
goto end ;
}
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
if ( switch_core_codec_init ( & vid_codec ,
h . video_codec_name ,
NULL ,
0 ,
0 ,
1 , SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE ,
NULL , switch_core_session_get_pool ( session ) ) = = SWITCH_STATUS_SUCCESS ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Video Codec Activation Success \n " ) ;
2008-02-09 00:37:58 +00:00
} else {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Video Codec Activation Fail \n " ) ;
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " Video codec activation failed " ) ;
2008-02-09 00:37:58 +00:00
goto end ;
}
switch_core_session_set_read_codec ( session , & codec ) ;
2012-01-17 12:19:23 -06:00
switch_core_service_session_av ( session , SWITCH_FALSE , SWITCH_TRUE ) ;
2008-05-27 04:54:52 +00:00
while ( switch_channel_ready ( channel ) ) {
2008-02-09 00:37:58 +00:00
if ( read ( fd , & bytes , sizeof ( bytes ) ) ! = sizeof ( bytes ) ) {
break ;
}
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
if ( bytes & VID_BIT ) {
2008-02-20 20:07:19 +00:00
switch_rtp_hdr_t * hdr = vid_frame . packet ;
2008-02-09 00:37:58 +00:00
bytes & = ~ VID_BIT ;
2008-05-27 04:54:52 +00:00
if ( ( vid_frame . packetlen = read ( fd , vid_frame . packet , bytes ) ) ! = ( uint32_t ) bytes ) {
2008-02-09 00:37:58 +00:00
break ;
}
2008-05-27 04:54:52 +00:00
2008-02-20 20:07:19 +00:00
ts = ntohl ( hdr - > ts ) ;
2008-02-11 17:14:14 +00:00
if ( pt ) {
2008-02-20 20:07:19 +00:00
hdr - > pt = pt ;
2008-02-11 17:14:14 +00:00
}
2008-02-09 00:37:58 +00:00
if ( switch_channel_test_flag ( channel , CF_VIDEO ) ) {
2010-01-07 16:40:38 +00:00
switch_byte_t * data = ( switch_byte_t * ) vid_frame . packet ;
2012-07-15 18:48:51 +08:00
vid_frame . m = hdr - > m ;
vid_frame . timestamp = ts ;
2010-01-07 16:40:38 +00:00
vid_frame . data = data + 12 ;
vid_frame . datalen = vid_frame . packetlen - 12 ;
2008-05-08 19:19:47 +00:00
switch_core_session_write_video_frame ( session , & vid_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2008-02-09 00:37:58 +00:00
}
if ( ts & & last & & last ! = ts ) {
2008-11-14 23:31:21 +00:00
switch_cond_next ( ) ;
2008-02-09 00:37:58 +00:00
}
last = ts ;
} else {
2008-05-27 04:54:52 +00:00
if ( bytes > ( int ) write_frame . buflen ) {
2008-02-09 00:37:58 +00:00
bytes = write_frame . buflen ;
}
2011-05-27 19:14:00 -05:00
2008-02-09 00:37:58 +00:00
if ( ( write_frame . datalen = read ( fd , write_frame . data , bytes ) ) < = 0 ) {
break ;
}
2008-05-08 19:19:47 +00:00
switch_core_session_write_frame ( session , & write_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2008-02-09 00:37:58 +00:00
switch_core_timer_next ( & timer ) ;
2011-05-27 19:14:00 -05:00
switch_core_session_read_frame ( session , & read_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
if ( switch_channel_test_flag ( channel , CF_BREAK ) ) {
switch_channel_clear_flag ( channel , CF_BREAK ) ;
break ;
}
switch_ivr_parse_all_events ( session ) ;
//check for dtmf interrupts
if ( switch_channel_has_dtmf ( channel ) ) {
const char * terminators = switch_channel_get_variable ( channel , SWITCH_PLAYBACK_TERMINATORS_VARIABLE ) ;
switch_channel_dequeue_dtmf ( channel , & dtmf ) ;
if ( terminators & & ! strcasecmp ( terminators , " none " ) )
{
terminators = NULL ;
}
if ( terminators & & strchr ( terminators , dtmf . digit ) ) {
char sbuf [ 2 ] = { dtmf . digit , ' \0 ' } ;
switch_channel_set_variable ( channel , SWITCH_PLAYBACK_TERMINATOR_USED , sbuf ) ;
break ;
}
}
}
2008-02-09 00:37:58 +00:00
}
2008-05-27 04:54:52 +00:00
2012-01-17 12:19:23 -06:00
switch_core_thread_session_end ( session ) ;
2011-05-27 19:14:00 -05:00
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " OK " ) ;
2008-05-27 04:54:52 +00:00
end :
2008-02-09 00:37:58 +00:00
if ( timer . interval ) {
switch_core_timer_destroy ( & timer ) ;
}
2010-01-07 16:40:38 +00:00
switch_core_session_set_read_codec ( session , NULL ) ;
2008-05-27 04:54:52 +00:00
2009-04-09 17:17:12 +00:00
if ( switch_core_codec_ready ( & codec ) ) {
2008-02-09 00:37:58 +00:00
switch_core_codec_destroy ( & codec ) ;
}
2008-05-27 04:54:52 +00:00
2009-04-09 17:17:12 +00:00
if ( switch_core_codec_ready ( & vid_codec ) ) {
2008-02-09 00:37:58 +00:00
switch_core_codec_destroy ( & vid_codec ) ;
}
2008-05-27 04:54:52 +00:00
2008-02-09 00:37:58 +00:00
if ( fd > - 1 ) {
close ( fd ) ;
}
}
2012-07-20 08:43:05 +08:00
struct fsv_file_context {
switch_file_t * fd ;
char * path ;
switch_mutex_t * mutex ;
} ;
typedef struct fsv_file_context fsv_file_context ;
static switch_status_t fsv_file_open ( switch_file_handle_t * handle , const char * path )
{
fsv_file_context * context ;
char * ext ;
unsigned int flags = 0 ;
if ( ( ext = strrchr ( path , ' . ' ) ) = = 0 ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Invalid Format \n " ) ;
return SWITCH_STATUS_GENERR ;
}
ext + + ;
if ( ( context = switch_core_alloc ( handle - > memory_pool , sizeof ( * context ) ) ) = = 0 ) {
return SWITCH_STATUS_MEMERR ;
}
switch_mutex_init ( & context - > mutex , SWITCH_MUTEX_NESTED , handle - > memory_pool ) ;
if ( switch_test_flag ( handle , SWITCH_FILE_FLAG_WRITE ) ) {
flags | = SWITCH_FOPEN_WRITE | SWITCH_FOPEN_CREATE ;
if ( switch_test_flag ( handle , SWITCH_FILE_WRITE_APPEND ) | | switch_test_flag ( handle , SWITCH_FILE_WRITE_OVER ) ) {
flags | = SWITCH_FOPEN_READ ;
} else {
flags | = SWITCH_FOPEN_TRUNCATE ;
}
}
if ( switch_test_flag ( handle , SWITCH_FILE_FLAG_READ ) ) {
flags | = SWITCH_FOPEN_READ ;
}
if ( switch_file_open ( & context - > fd , path , flags , SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE , handle - > memory_pool ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error opening %s \n " , path ) ;
return SWITCH_STATUS_GENERR ;
}
context - > path = switch_core_strdup ( handle - > memory_pool , path ) ;
if ( switch_test_flag ( handle , SWITCH_FILE_WRITE_APPEND ) ) {
int64_t samples = 0 ;
switch_file_seek ( context - > fd , SEEK_END , & samples ) ;
handle - > pos = samples ;
}
handle - > samples = 0 ;
handle - > samplerate = 8000 ;
handle - > channels = 1 ;
handle - > format = 0 ;
handle - > sections = 0 ;
handle - > seekable = 0 ;
handle - > speed = 0 ;
handle - > pos = 0 ;
handle - > private_info = context ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Opening File [%s] %dhz \n " , path , handle - > samplerate ) ;
if ( switch_test_flag ( handle , SWITCH_FILE_FLAG_WRITE ) ) {
struct file_header h ;
size_t len = sizeof ( h ) ;
memset ( & h , 0 , sizeof ( h ) ) ;
h . version = VERSION ;
h . created = switch_micro_time_now ( ) ;
switch_set_string ( h . video_codec_name , " H264 " ) ; /* FIXME: hard coded */
h . audio_rate = handle - > samplerate ;
h . audio_ptime = 20 ; /* FIXME: hard coded */
if ( switch_file_write ( context - > fd , & h , & len ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " File write failed \n " ) ;
return SWITCH_STATUS_GENERR ;
}
} else if ( switch_test_flag ( handle , SWITCH_FILE_FLAG_READ ) ) {
struct file_header h ;
size_t size = sizeof ( h ) ;
if ( switch_file_read ( context - > fd , & h , & size ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Error reading file header \n " ) ;
return SWITCH_STATUS_GENERR ;
}
if ( h . version ! = VERSION ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " File version does not match! \n " ) ;
return SWITCH_STATUS_GENERR ;
}
handle - > samplerate = h . audio_rate ;
}
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t fsv_file_truncate ( switch_file_handle_t * handle , int64_t offset )
{
fsv_file_context * context = handle - > private_info ;
switch_status_t status ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " truncate file [%s] \n " , context - > path ) ;
if ( ( status = switch_file_trunc ( context - > fd , offset ) ) = = SWITCH_STATUS_SUCCESS ) {
handle - > pos = 0 ;
}
return status ;
}
static switch_status_t fsv_file_close ( switch_file_handle_t * handle )
{
fsv_file_context * context = handle - > private_info ;
if ( context - > fd ) {
switch_file_close ( context - > fd ) ;
context - > fd = NULL ;
}
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t fsv_file_seek ( switch_file_handle_t * handle , unsigned int * cur_sample , int64_t samples , int whence )
{
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Seek not implemented \n " ) ;
return SWITCH_STATUS_FALSE ;
}
static switch_status_t fsv_file_read ( switch_file_handle_t * handle , void * data , size_t * len )
{
switch_status_t status ;
size_t need = * len ;
uint32_t size ;
size_t bytes = sizeof ( size ) ;
fsv_file_context * context = handle - > private_info ;
again :
status = switch_file_read ( context - > fd , & size , & bytes ) ;
if ( status ! = SWITCH_STATUS_SUCCESS ) {
goto end ;
}
if ( size & VID_BIT ) { /* video */
* len = size & ~ VID_BIT ;
/* TODO: read video data */
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " discarding video data %d \n " , ( int ) * len ) ;
status = switch_file_read ( context - > fd , data , len ) ;
if ( status ! = SWITCH_STATUS_SUCCESS ) {
goto end ;
}
handle - > pos + = * len + bytes ;
goto again ;
}
if ( size > need ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " size %u > need %u \n " , ( unsigned int ) size , ( int ) need ) ;
goto end ;
}
* len = size ;
status = switch_file_read ( context - > fd , data , len ) ;
* len / = 2 ;
end :
return status ;
}
static switch_status_t fsv_file_write ( switch_file_handle_t * handle , void * data , size_t * len )
{
uint32_t datalen = * len * 2 ;
size_t size ;
switch_status_t status ;
fsv_file_context * context = handle - > private_info ;
/* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "writing: %ld\n", (long)(*len)); */
if ( * len > 160 ) { /* when sample rate is 8000 */
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " You are asking to write %d bytes of data which is not supported. Please set enable_file_write_buffering=false to use .fsv format \n " , ( int ) ( * len ) ) ;
return SWITCH_STATUS_GENERR ;
}
switch_mutex_lock ( context - > mutex ) ;
size = sizeof ( datalen ) ;
if ( switch_file_write ( context - > fd , & datalen , & size ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " write error \n " ) ;
return SWITCH_STATUS_FALSE ;
}
* len = datalen ;
status = switch_file_write ( context - > fd , data , len ) ;
switch_mutex_unlock ( context - > mutex ) ;
return status ;
}
2012-07-20 11:38:20 +08:00
static switch_status_t fsv_file_write_video ( switch_file_handle_t * handle , void * data , size_t * len )
{
uint32_t datalen = * len ;
uint32_t bytes = datalen | VID_BIT ;
size_t size ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2012-07-20 08:43:05 +08:00
2012-07-20 11:38:20 +08:00
fsv_file_context * context = handle - > private_info ;
/* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "writing: %ld\n", (long)(*len)); */
2012-07-20 08:43:05 +08:00
2012-07-20 11:38:20 +08:00
switch_mutex_lock ( context - > mutex ) ;
2012-07-20 08:43:05 +08:00
2012-07-20 11:38:20 +08:00
size = sizeof ( bytes ) ;
if ( switch_file_write ( context - > fd , & bytes , & size ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " write error \n " ) ;
return SWITCH_STATUS_FALSE ;
}
2012-07-20 08:43:05 +08:00
2012-07-20 11:38:20 +08:00
* len = datalen ;
status = switch_file_write ( context - > fd , data , len ) ;
switch_mutex_unlock ( context - > mutex ) ;
2012-07-20 08:43:05 +08:00
2012-07-20 11:38:20 +08:00
return status ;
}
2012-07-20 08:43:05 +08:00
static switch_status_t fsv_file_set_string ( switch_file_handle_t * handle , switch_audio_col_t col , const char * string )
{
return SWITCH_STATUS_FALSE ;
}
static switch_status_t fsv_file_get_string ( switch_file_handle_t * handle , switch_audio_col_t col , const char * * string )
{
return SWITCH_STATUS_FALSE ;
}
/* Registration */
static char * supported_formats [ 2 ] = { 0 } ;
2008-02-09 00:37:58 +00:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_fsv_load )
{
switch_application_interface_t * app_interface ;
2012-07-20 08:43:05 +08:00
switch_file_interface_t * file_interface ;
supported_formats [ 0 ] = " fsv " ;
2008-02-09 00:37:58 +00:00
/* connect my internal structure to the blank pointer passed to me */
2008-05-27 04:54:52 +00:00
* module_interface = switch_loadable_module_create_module_interface ( pool , modname ) ;
2008-02-09 00:37:58 +00:00
2012-07-20 08:43:05 +08:00
file_interface = switch_loadable_module_create_interface ( * module_interface , SWITCH_FILE_INTERFACE ) ;
file_interface - > interface_name = modname ;
file_interface - > extens = supported_formats ;
file_interface - > file_open = fsv_file_open ;
file_interface - > file_close = fsv_file_close ;
file_interface - > file_truncate = fsv_file_truncate ;
file_interface - > file_read = fsv_file_read ;
file_interface - > file_write = fsv_file_write ;
2012-07-20 11:38:20 +08:00
file_interface - > file_write_video = fsv_file_write_video ;
2012-07-20 08:43:05 +08:00
file_interface - > file_seek = fsv_file_seek ;
file_interface - > file_set_string = fsv_file_set_string ;
file_interface - > file_get_string = fsv_file_get_string ;
2008-02-09 00:37:58 +00:00
SWITCH_ADD_APP ( app_interface , " play_fsv " , " play an fsv file " , " play an fsv file " , play_fsv_function , " <file> " , SAF_NONE ) ;
SWITCH_ADD_APP ( app_interface , " record_fsv " , " record an fsv file " , " record an fsv file " , record_fsv_function , " <file> " , SAF_NONE ) ;
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS ;
}
/* For Emacs:
* Local Variables :
* mode : c
* indent - tabs - mode : t
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
2008-07-03 19:12:26 +00:00
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 :
2008-02-09 00:37:58 +00:00
*/