2008-02-09 00:37:58 +00:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
2014-02-05 15:02:28 -06:00
* Copyright ( C ) 2005 - 2014 , 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
2013-06-17 19:52:37 -05:00
switch_channel_set_flag ( channel , CF_VIDEO_PASSIVE ) ;
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 ) ;
2013-09-10 01:52:21 +08:00
switch_core_session_refresh_video ( session ) ;
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 " ) ;
2013-06-17 19:52:37 -05:00
goto done ;
2010-03-25 19:08:00 +00:00
}
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 " ) ;
2013-06-17 19:52:37 -05:00
goto done ;
2010-03-25 19:06:18 +00:00
}
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 " ) ;
2013-06-17 19:52:37 -05:00
goto done ;
2008-02-09 00:37:58 +00:00
}
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
2013-06-17 19:52:37 -05:00
done :
switch_channel_clear_flag ( channel , CF_VIDEO_PASSIVE ) ;
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
2013-06-17 19:52:37 -05:00
switch_channel_set_flag ( channel , CF_VIDEO_PASSIVE ) ;
2013-09-10 01:52:21 +08:00
switch_core_session_refresh_video ( session ) ;
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 " ) ;
2013-06-17 19:52:37 -05:00
goto done ;
2008-02-09 00:37:58 +00:00
}
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 ;
}
2013-02-16 17:59:59 -06:00
switch_channel_set_variable ( channel , " rtp_force_video_fmtp " , h . video_fmtp ) ;
2008-02-09 00:37:58 +00:00
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 ;
2013-01-21 23:18:16 +01:00
/*
* Frame is larger than available buffer space . This error is non - recoverable due to the
* structure of the . fsv format ( no frame header signature to re - sync ) .
*/
if ( bytes > ( ( int ) vid_frame . buflen + 12 ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Corrupt .fsv video frame header is overflowing read buffer, aborting! \n " ) ;
break ;
}
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 {
2013-01-21 23:18:16 +01:00
/*
* Frame is larger than available buffer space . This error is non - recoverable due to the
* structure of the . fsv format ( no frame header signature to re - sync ) .
*/
2008-05-27 04:54:52 +00:00
if ( bytes > ( int ) write_frame . buflen ) {
2013-01-21 23:18:16 +01:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Corrupt .fsv audio frame header is overflowing read buffer, aborting! \n " ) ;
break ;
2008-02-09 00:37:58 +00:00
}
2013-01-21 23:18:16 +01: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 ) ;
}
2013-06-17 19:52:37 -05:00
done :
switch_channel_clear_flag ( channel , CF_VIDEO_PASSIVE ) ;
2008-02-09 00:37:58 +00:00
}
2014-07-26 08:36:02 +08:00
uint8_t art [ 14 ] [ 16 ] = {
{ 0x00 , 0x7E , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x7E , 0x00 } ,
{ 0x00 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x00 } ,
{ 0x00 , 0x7E , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x7E , 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x7E , 0x00 } ,
{ 0x00 , 0x7E , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x7E , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x7E , 0x00 } ,
{ 0x00 , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x7E , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x00 } ,
{ 0x00 , 0x7E , 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x7E , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x7E , 0x00 } ,
{ 0x00 , 0x7E , 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x7E , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x7E , 0x00 } ,
{ 0x00 , 0x7E , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x00 } ,
{ 0x00 , 0x7E , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x7E , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x7E , 0x00 } ,
{ 0x00 , 0x7E , 0x42 , 0x42 , 0x42 , 0x42 , 0x42 , 0x7E , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x02 , 0x7E , 0x00 } ,
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x20 , 0x00 , 0x00 , 0x00 } , /*.*/
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x20 , 0x00 , 0x00 , 0x00 , 0x20 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } , /*:*/
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x7E , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } , /*-*/
{ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } , /* */
} ;
void tag ( void * buffer , int w , int x , int y , uint8_t n )
{
int i = 0 , j = 0 ;
uint8_t * p = buffer ;
if ( n < 0 | | n > 13 ) return ;
for ( i = 0 ; i < 8 ; i + + ) {
for ( j = 0 ; j < 16 ; j + + ) {
* ( p + ( y + j ) * w + ( x + i ) ) = ( art [ n ] [ j ] & 0x80 > > i ) ? 0xFF : 0x00 ;
}
}
}
void text ( void * buffer , int w , int x , int y , char * s )
{
while ( * s ) {
int index ;
if ( x > w - 8 ) break ;
switch ( * s ) {
case ' . ' : index = 10 ; break ;
case ' : ' : index = 11 ; break ;
case ' - ' : index = 12 ; break ;
case ' ' : index = 13 ; break ;
default :
index = * s - 0x30 ;
}
tag ( buffer , w , x , y , index ) ;
x + = 8 ;
s + + ;
}
}
/*
\ brief play YUV file in I420 ( YV12 ) format
*/
SWITCH_STANDARD_APP ( play_yuv_function )
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
switch_frame_t vid_frame = { 0 } ;
int fd = - 1 ;
switch_codec_t * codec = NULL ;
unsigned char * vid_buffer ;
// switch_timer_t timer = { 0 };
switch_dtmf_t dtmf = { 0 } ;
switch_frame_t * read_frame ;
uint32_t width = 0 , height = 0 , size ;
2014-08-04 03:15:26 +08:00
switch_image_t * img = NULL ;
switch_byte_t * yuv = NULL ;
2014-07-26 08:36:02 +08:00
int argc ;
char * argv [ 3 ] = { 0 } ;
char * mydata = switch_core_session_strdup ( session , data ) ;
2014-08-04 03:15:26 +08:00
if ( ! switch_channel_test_flag ( channel , CF_VIDEO ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Channel %s has no video \n " , switch_channel_get_name ( channel ) ) ;
goto done ;
}
2014-07-26 08:36:02 +08:00
argc = switch_separate_string ( mydata , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ;
if ( argc = = 0 ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " No file present \n " ) ;
goto done ;
}
if ( argc > 1 ) width = atoi ( argv [ 1 ] ) ;
if ( argc > 2 ) height = atoi ( argv [ 2 ] ) ;
width = width ? width : 352 ;
height = height ? height : 288 ;
size = width * height * 3 / 2 ;
2014-08-04 03:15:26 +08:00
img = switch_img_alloc ( NULL , SWITCH_IMG_FMT_I420 , width , height , 0 ) ;
if ( ! img ) {
2014-07-26 08:36:02 +08:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Memory Error \n " ) ;
goto end ;
}
2014-08-04 03:15:26 +08:00
yuv = img - > planes [ SWITCH_PLANE_PACKED ] ;
2014-07-26 08:36:02 +08:00
// switch_channel_set_flag(channel, CF_VIDEO_PASSIVE);
switch_channel_clear_flag ( channel , CF_VIDEO_ECHO ) ;
vid_buffer = switch_core_session_alloc ( session , SWITCH_RECOMMENDED_BUFFER_SIZE ) ;
switch_channel_set_variable ( channel , SWITCH_PLAYBACK_TERMINATOR_USED , " " ) ;
if ( ( fd = open ( argv [ 0 ] , O_RDONLY | O_BINARY ) ) < 0 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " Error opening file %s \n " , ( char * ) data ) ;
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " Got error while opening file " ) ;
goto end ;
}
if ( read ( fd , yuv , size ) ! = size ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " Error reading file \n " ) ;
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " Got error reading file " ) ;
goto end ;
}
close ( fd ) ;
fd = - 1 ;
switch_channel_answer ( channel ) ;
codec = switch_core_session_get_video_write_codec ( session ) ;
vid_frame . codec = 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 ) ;
// switch_set_flag((&vid_frame), SFF_PROXY_PACKET);
while ( switch_channel_ready ( channel ) ) {
2014-11-19 18:59:53 +08:00
char ts_str [ 64 ] ;
2014-07-26 08:36:02 +08: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 ;
}
}
2014-11-19 17:37:33 -06:00
/* echo of opus tends to seg chrome */
//if (read_frame) switch_core_session_write_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
2014-07-26 08:36:02 +08:00
2014-11-19 18:59:53 +08:00
sprintf ( ts_str , " % " SWITCH_TIME_T_FMT , switch_micro_time_now ( ) / 1000 ) ;
text ( img - > planes [ SWITCH_PLANE_PACKED ] , width , 20 , 20 , ts_str ) ;
vid_frame . img = img ;
switch_core_session_write_video_frame ( session , & vid_frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2014-07-26 08:36:02 +08:00
}
switch_core_thread_session_end ( session ) ;
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " OK " ) ;
end :
if ( fd > - 1 ) {
close ( fd ) ;
}
2014-08-04 03:15:26 +08:00
switch_img_free ( img ) ;
2014-07-26 08:36:02 +08:00
done :
// switch_channel_clear_flag(channel, CF_VIDEO_PASSIVE);
switch_channel_set_flag ( channel , CF_VIDEO_ECHO ) ;
}
2014-07-28 06:41:58 +08:00
SWITCH_STANDARD_APP ( decode_video_function )
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
switch_codec_t * codec = NULL ;
switch_frame_t * frame ;
uint32_t width = 0 , height = 0 ;
uint32_t max_pictures = 0 ;
uint32_t decoded_pictures = 0 ;
if ( ! zstr ( data ) ) max_pictures = atoi ( data ) ;
if ( ! switch_channel_test_flag ( channel , CF_VIDEO ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Channel %s has no video \n " , switch_channel_get_name ( channel ) ) ;
goto done ;
}
2014-08-04 03:15:26 +08:00
switch_channel_set_flag ( channel , CF_VIDEO_PASSIVE ) ;
switch_channel_clear_flag ( channel , CF_VIDEO_ECHO ) ;
switch_channel_answer ( channel ) ;
2014-07-28 06:41:58 +08:00
switch_core_session_refresh_video ( session ) ;
switch_channel_set_variable ( channel , SWITCH_PLAYBACK_TERMINATOR_USED , " " ) ;
codec = switch_core_session_get_video_read_codec ( session ) ;
if ( ! codec ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Channel has no video read codec \n " ) ;
goto done ;
}
2014-11-20 23:19:20 +08:00
switch_channel_set_flag ( channel , CF_VIDEO_DECODED_READ ) ;
2014-07-28 06:41:58 +08:00
while ( switch_channel_ready ( channel ) ) {
2014-11-20 23:19:20 +08:00
switch_status_t status = switch_core_session_read_video_frame ( session , & frame , SWITCH_IO_FLAG_NONE , 0 ) ;
2014-07-28 06:41:58 +08:00
if ( switch_channel_test_flag ( channel , CF_BREAK ) ) {
switch_channel_clear_flag ( channel , CF_BREAK ) ;
break ;
}
2014-11-20 23:19:20 +08:00
if ( ! SWITCH_READ_ACCEPTABLE ( status ) ) {
break ;
2014-07-28 06:41:58 +08:00
}
2014-08-04 03:15:26 +08:00
if ( frame & & frame - > datalen > 0 ) {
2014-07-28 06:41:58 +08:00
switch_core_session_write_video_frame ( session , frame , SWITCH_IO_FLAG_NONE , 0 ) ;
} else {
continue ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " seq: %d ts: %ld len: %4d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x mark: %d %s \n " ,
frame - > seq , frame - > timestamp , frame - > datalen ,
* ( ( uint8_t * ) frame - > data ) , * ( ( uint8_t * ) frame - > data + 1 ) ,
* ( ( uint8_t * ) frame - > data + 2 ) , * ( ( uint8_t * ) frame - > data + 3 ) ,
* ( ( uint8_t * ) frame - > data + 4 ) , * ( ( uint8_t * ) frame - > data + 5 ) ,
* ( ( uint8_t * ) frame - > data + 6 ) , * ( ( uint8_t * ) frame - > data + 7 ) ,
* ( ( uint8_t * ) frame - > data + 8 ) , * ( ( uint8_t * ) frame - > data + 9 ) ,
* ( ( uint8_t * ) frame - > data + 10 ) , frame - > m , switch_test_flag ( frame , SFF_CNG ) ? " CNG " : " " ) ;
2014-08-04 03:15:26 +08:00
if ( switch_test_flag ( frame , SFF_CNG ) | | frame - > datalen < 3 ) {
2014-07-28 06:41:58 +08:00
continue ;
}
2014-11-20 23:19:20 +08:00
if ( frame - > img ) {
if ( frame - > img - > d_w > 0 & & ! width ) {
width = frame - > img - > d_w ;
switch_channel_set_variable_printf ( channel , " video_width " , " %d " , width ) ;
2014-07-28 06:41:58 +08:00
}
2014-11-20 23:19:20 +08:00
if ( frame - > img - > d_h > 0 & & ! height ) {
height = frame - > img - > d_h ;
switch_channel_set_variable_printf ( channel , " video_height " , " %d " , height ) ;
}
2014-07-28 06:41:58 +08:00
2014-11-20 23:19:20 +08:00
decoded_pictures + + ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " picture#%d %dx%d \n " , decoded_pictures , frame - > img - > d_w , frame - > img - > d_h ) ;
2014-07-28 06:41:58 +08:00
2014-11-20 23:19:20 +08:00
if ( max_pictures & & ( decoded_pictures > = max_pictures ) ) {
break ;
2014-07-28 06:41:58 +08:00
}
}
}
switch_core_thread_session_end ( session ) ;
switch_channel_set_variable ( channel , SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE , " OK " ) ;
done :
switch_channel_clear_flag ( channel , CF_VIDEO_PASSIVE ) ;
switch_channel_set_flag ( channel , CF_VIDEO_ECHO ) ;
}
/* File Interface*/
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 ;
2012-08-29 11:35:32 +08:00
// handle->samplerate = 8000;
// handle->channels = 1;
2012-07-20 08:43:05 +08:00
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 )
{
2012-08-29 11:35:32 +08:00
uint32_t datalen = * len * sizeof ( int16_t ) ;
2012-07-20 08:43:05 +08:00
size_t size ;
switch_status_t status ;
2012-08-29 11:35:32 +08:00
int16_t * xdata = data ;
int max_datasize = handle - > samplerate / 8000 * 160 ;
2012-07-20 08:43:05 +08:00
fsv_file_context * context = handle - > private_info ;
2012-08-29 11:35:32 +08:00
/* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "writing: %ld %d %x\n", (long)(*len), handle->channels, handle->flags); */
2012-07-20 08:43:05 +08:00
2012-08-29 11:35:32 +08:00
if ( * len > max_datasize ) {
2012-07-20 08:43:05 +08:00
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 ;
}
2012-08-29 11:35:32 +08:00
if ( handle - > channels > 1 ) {
int i , j ;
int32_t mixed = 0 ;
for ( i = 0 ; i < * len ; i + + ) {
for ( j = 0 ; j < handle - > channels ; j + + ) {
mixed + = xdata [ i * handle - > channels + j ] ;
}
switch_normalize_to_16bit ( mixed ) ;
xdata [ i ] = ( uint16_t ) mixed ;
}
}
2012-07-20 08:43:05 +08:00
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 ) ;
2012-08-29 11:35:32 +08:00
handle - > sample_count + = * len / sizeof ( int16_t ) ;
2012-07-20 08:43:05 +08:00
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 )
{
2014-01-22 22:28:53 +01:00
uint32_t datalen = ( uint32_t ) * len ;
2012-07-20 11:38:20 +08:00
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-08-29 11:35:32 +08:00
* len / = 2 ;
handle - > sample_count + = * len ;
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 ;
2014-07-26 08:36:02 +08:00
SWITCH_ADD_APP ( app_interface , " play_fsv " , " play a fsv file " , " play a fsv file " , play_fsv_function , " <file> " , SAF_NONE ) ;
2008-02-09 00:37:58 +00:00
SWITCH_ADD_APP ( app_interface , " record_fsv " , " record an fsv file " , " record an fsv file " , record_fsv_function , " <file> " , SAF_NONE ) ;
2014-07-28 06:41:58 +08:00
SWITCH_ADD_APP ( app_interface , " play_yuv " , " play a yvv file " , " play a yvv file in I420 format " , play_yuv_function , " <file> [width] [height] " , SAF_NONE ) ;
SWITCH_ADD_APP ( app_interface , " decode_video " , " decode picture " , " decode picture and dump to log " , decode_video_function , " [max_pictures] " , SAF_NONE ) ;
2008-02-09 00:37:58 +00:00
/* 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 :
2013-06-25 11:50:17 -05:00
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 noet :
2008-02-09 00:37:58 +00:00
*/