@ -127,6 +127,11 @@
Like with the basic filename argument , if an absolute path isn ' t given , it will create
Like with the basic filename argument , if an absolute path isn ' t given , it will create
the file in the configured monitoring directory . < / para >
the file in the configured monitoring directory . < / para >
< / option >
< / option >
< option name = " D " >
< para > Interleave the audio coming from the channel and the audio coming to the channel in
the output audio as a dual channel stream , rather than mix it . < / para >
< note > < para > Use . raw as the extension . < / para > < / note >
< / option >
< option name = " n " >
< option name = " n " >
< para > When the < replaceable > r < / replaceable > or < replaceable > t < / replaceable > option is
< para > When the < replaceable > r < / replaceable > or < replaceable > t < / replaceable > option is
used , MixMonitor will insert silence into the specified files to maintain
used , MixMonitor will insert silence into the specified files to maintain
@ -418,6 +423,7 @@ enum mixmonitor_flags {
MUXFLAG_NO_RWSYNC = ( 1 < < 15 ) ,
MUXFLAG_NO_RWSYNC = ( 1 < < 15 ) ,
MUXFLAG_AUTO_DELETE = ( 1 < < 16 ) ,
MUXFLAG_AUTO_DELETE = ( 1 < < 16 ) ,
MUXFLAG_REAL_CALLERID = ( 1 < < 17 ) ,
MUXFLAG_REAL_CALLERID = ( 1 < < 17 ) ,
MUXFLAG_INTERLEAVED = ( 1 < < 18 ) ,
} ;
} ;
enum mixmonitor_args {
enum mixmonitor_args {
@ -447,6 +453,7 @@ AST_APP_OPTIONS(mixmonitor_opts, {
AST_APP_OPTION_ARG ( ' W ' , MUXFLAG_VOLUME , OPT_ARG_VOLUME ) ,
AST_APP_OPTION_ARG ( ' W ' , MUXFLAG_VOLUME , OPT_ARG_VOLUME ) ,
AST_APP_OPTION_ARG ( ' r ' , MUXFLAG_READ , OPT_ARG_READNAME ) ,
AST_APP_OPTION_ARG ( ' r ' , MUXFLAG_READ , OPT_ARG_READNAME ) ,
AST_APP_OPTION_ARG ( ' t ' , MUXFLAG_WRITE , OPT_ARG_WRITENAME ) ,
AST_APP_OPTION_ARG ( ' t ' , MUXFLAG_WRITE , OPT_ARG_WRITENAME ) ,
AST_APP_OPTION ( ' D ' , MUXFLAG_INTERLEAVED ) ,
AST_APP_OPTION_ARG ( ' i ' , MUXFLAG_UID , OPT_ARG_UID ) ,
AST_APP_OPTION_ARG ( ' i ' , MUXFLAG_UID , OPT_ARG_UID ) ,
AST_APP_OPTION_ARG ( ' m ' , MUXFLAG_VMRECIPIENTS , OPT_ARG_VMRECIPIENTS ) ,
AST_APP_OPTION_ARG ( ' m ' , MUXFLAG_VMRECIPIENTS , OPT_ARG_VMRECIPIENTS ) ,
AST_APP_OPTION_ARG ( ' S ' , MUXFLAG_DEPRECATED_RWSYNC , OPT_ARG_DEPRECATED_RWSYNC ) ,
AST_APP_OPTION_ARG ( ' S ' , MUXFLAG_DEPRECATED_RWSYNC , OPT_ARG_DEPRECATED_RWSYNC ) ,
@ -797,6 +804,46 @@ static void *mixmonitor_thread(void *obj)
}
}
}
}
if ( ast_test_flag ( mixmonitor , MUXFLAG_INTERLEAVED ) ) {
/* The 'D' option is set, so mix the frame as an interleaved dual channel frame */
int i ;
short read_buf [ SAMPLES_PER_FRAME ] ;
short write_buf [ SAMPLES_PER_FRAME ] ;
short stereo_buf [ SAMPLES_PER_FRAME * 2 ] ;
struct ast_frame stereo_frame = {
. frametype = AST_FRAME_VOICE ,
. datalen = sizeof ( stereo_buf ) ,
. samples = SAMPLES_PER_FRAME ,
} ;
if ( fr ) {
ast_frame_free ( fr , 0 ) ;
fr = NULL ;
}
if ( fr_read ) {
memcpy ( read_buf , fr_read - > data . ptr , sizeof ( read_buf ) ) ;
} else {
memset ( read_buf , 0 , sizeof ( read_buf ) ) ;
}
if ( fr_write ) {
memcpy ( write_buf , fr_write - > data . ptr , sizeof ( write_buf ) ) ;
} else {
memset ( write_buf , 0 , sizeof ( write_buf ) ) ;
}
for ( i = 0 ; i < SAMPLES_PER_FRAME ; i + + ) {
stereo_buf [ i * 2 ] = read_buf [ i ] ;
stereo_buf [ i * 2 + 1 ] = write_buf [ i ] ;
}
stereo_frame . data . ptr = stereo_buf ;
stereo_frame . subclass . format = ast_format_cache_get_slin_by_rate ( SAMPLES_PER_FRAME ) ;
fr = ast_frdup ( & stereo_frame ) ;
}
if ( ( * fs ) & & ( fr ) ) {
if ( ( * fs ) & & ( fr ) ) {
struct ast_frame * cur ;
struct ast_frame * cur ;