1 /*******************************************************************************
2 * intf_ctrl.c: interface commands access to control functions
4 *******************************************************************************
5 * Library of functions common to all interfaces, allowing access to various
6 * structures and settings. Interfaces should only use those functions
7 * to read or write informations from other threads.
8 * A control function must be declared in the `local prototypes' section (it's
9 * type is fixed), and copied into the control_command array. Functions should
10 * be listed in alphabetical order, so when `help' is called they are also
11 * displayed in this order.
12 * A control function can use any function of the program, but should respect
13 * two points: first, it should not block, since if it does so, the whole
14 * interface thread will hang and in particular miscelannous interface events
15 * won't be handled. Secondly, it should send it's output messages exclusively
16 * with intf_IntfMsg() function, except particularly critical messages which
17 * can use over intf_*Msg() functions.
18 * Control functions should return 0 (INTF_NO_ERROR) on success, or one of the
19 * error codes defined in command.h. Custom error codes are allowed, but should
21 * More informations about parameters stand in `list of commands' section.
22 *******************************************************************************/
24 /*******************************************************************************
26 *******************************************************************************/
29 #include <netinet/in.h>
34 #include <sys/soundcard.h>
38 #include <X11/extensions/XShm.h>
43 #include "vlc_thread.h"
49 #include "input_ctrl.h"
50 #include "input_vlan.h"
51 #include "input_psi.h"
52 #include "input_netlist.h"
53 #include "decoder_fifo.h"
55 #include "audio_output.h"
56 #include "audio_decoder.h"
59 #include "video_output.h"
60 #include "video_graphics.h"
61 #include "video_decoder.h"
64 #include "interface.h"
67 #include "intf_ctrl.h"
74 static int Demo ( int i_argc, intf_arg_t *p_argv );
75 static int DisplayImage ( int i_argc, intf_arg_t *p_argv );
76 static int Exec ( int i_argc, intf_arg_t *p_argv );
77 static int Help ( int i_argc, intf_arg_t *p_argv );
78 static int PlayAudio ( int i_argc, intf_arg_t *p_argv );
79 static int PlayVideo ( int i_argc, intf_arg_t *p_argv );
80 static int Quit ( int i_argc, intf_arg_t *p_argv );
81 static int SelectPID ( int i_argc, intf_arg_t *p_argv );
82 static int SpawnInput ( int i_argc, intf_arg_t *p_argv );
84 static int Test ( int i_argc, intf_arg_t *p_argv );
86 static int Vlan ( int i_argc, intf_arg_t *p_argv );
87 static int Psi ( int i_argc, intf_arg_t *p_argv );
91 * This list is used by intf_ExecCommand function to find functions to
92 * execute and prepare its arguments. It is terminated by an element which name
93 * is a null pointer. intf_command_t is defined in command.h.
95 * Here is a description of a command description elements:
96 * name is the name of the function, as it should be typed on command line,
97 * function is a pointer to the control function,
98 * format is an argument descriptor (see below),
99 * summary is a text string displayed in regard of the command name when `help'
100 * is called without parameters, and whith usage on syntax error,
101 * usage is a short syntax indicator displayed with summary when the command
102 * causes a syntax error,
103 * help is a complete help about the command, displayed when `help' is called with
104 * the command name as parameter.
106 * Format string is a list of ' ' separated strings, which have following
111 * ? optionnal argument
112 * * argument can be repeated
113 * name= named argument
114 * Example: "channel=i? s*? i " means that any number of string arguments,
115 * followed by a single mandatory integer argument are waited. A named argument,
116 * which name is `channel' and must have an integer value can be optionnaly
117 * specified at beginning. The last space is mandatory if there is at least one
118 * element, since it acts as an item terminator.
119 * Named arguments MUST be at the beginning of the format string, and in
120 * alphabetic order, but their order on command line has no importance.
121 * The format string can't have more than INTF_MAX_ARGS elements.
123 const intf_command_t control_command[] =
125 { "demo", Demo, /* demo */
127 /* summary: */ "program demonstration",
129 /* help: */ "Start program capabilities demonstration." },
130 { "display", DisplayImage, /* display */
132 /* summary: */ "load and display an image",
133 /* usage: */ "display <file>",
134 /* help: */ "Load and display an image. Image format is automatically " \
135 "identified from file name extension." },
136 { "exec", Exec, /* exec */
138 /* summary: */ "execute a script file",
139 /* usage: */ "exec <file>",
140 /* help: */ "Load an execute a script." },
141 { "exit", Quit, /* exit (quit alias) */
143 /* summary: */ "quit program",
145 /* help: */ "see `quit'." },
146 { "help", Help, /* help */
148 /* summary: */ "list all functions or print help about a specific function",
149 /* usage: */ "help [command]",
150 /* help: */ "If called without argument, list all available " \
151 " functions.\nIf a command name is provided as argument, displays a short " \
152 "inline help about the command.\n" },
153 { "play-audio", PlayAudio, /* play-audio */
154 /* format: */ "stereo=i? rate=i? s ",
155 /* summary: */ "play an audio file",
156 /* usage: */ "play-audio [stereo=1/0] [rate=r] <file>",
157 /* help: */ "Load and play an audio file." },
158 { "play-video", PlayVideo, /* play-video */
160 /* summary: */ "play a video (.vlp) file",
161 /* usage: */ "play-video <file>",
162 /* help: */ "Load and play a video file." },
163 { "quit", Quit, /* quit */
165 /* summary: */ "quit program",
167 /* help: */ "Terminates the program execution... There is not much to" \
169 { "select-pid", SelectPID, /* select-pid */
170 /* format: */ "i i ",
171 /* summary: */ "spawn a decoder thread for a specified PID",
172 /* summary: */ "select-pid <input> <pid>",
173 /* help: */ "Spawn a decoder thread for <pid>. The stream will be" \
174 " received by <input>." },
175 { "spawn-input", SpawnInput, /* spawn-input */
176 /* format: */ "method=i? filename=s? hostname=s? ip=s? port=i? vlan=i?",
177 /* summary: */ "spawn an input thread",
178 /* summary: */ "spawn-input [method=<method>]\n" \
179 "[filename=<file>|hostname=<hostname>|ip=<ip>]\n" \
180 "[port=<port>] [vlan=<vlan>]",
181 /* help: */ "Spawn an input thread. Method is 10, 20, 21, 22, 32, "\
182 "hostname is the fully-qualified domain name, ip is a dotted-decimal address." },
184 { "test", Test, /* test */
186 /* summary: */ "crazy developper's test",
187 /* usage: */ "depends on the last coder :-)",
188 /* help: */ "`test' works only in DEBUG mode, and is provide for " \
189 "developpers as an easy way to test part of their code. If you don't know " \
190 "what it should do, just try !" },
193 /* format: */ "intf=s? s i? ",
194 /* summary: */ "vlan operations",
195 /* usage: */ "vlan synchro\n" \
196 "vlan [intf=<interface>] request\n" \
197 "vlan [intf=<interface>] join <vlan>\n" \
198 "vlan [intf=<interface>] leave"
199 /* help: */ "Perform various operations on vlans. 'synchro' resynchronize " \
200 "with the server. 'request' ask which is the current vlan (for the default " \
201 "interface or for a given one). 'join' and 'leave' try to change vlan." },
204 /* summary: */ "Dump PSI tables",
205 /* usage: */ "psi <input thread index>",
206 /* help: */ "Display the PSI tables on the console. Warning: this is debug" \
207 "command, it can leads to pb since locks are not taken yet" },
208 { 0, 0, 0, 0, 0 } /* array terminator */
211 /* following functions are local */
213 /*******************************************************************************
215 *******************************************************************************
216 * This function is provided to display a demo of program possibilities.
217 *******************************************************************************/
218 static int Demo( int i_argc, intf_arg_t *p_argv )
220 intf_IntfMsg( COPYRIGHT_MESSAGE );
222 return( INTF_NO_ERROR );
225 /*******************************************************************************
226 * Exec: execute a script
227 *******************************************************************************
228 * This function load and execute a script.
229 *******************************************************************************/
230 static int Exec( int i_argc, intf_arg_t *p_argv )
232 int i_err; /* error code */
234 i_err = intf_ExecScript( p_argv[1].psz_str );
235 return( i_err ? INTF_OTHER_ERROR : INTF_NO_ERROR );
238 /*******************************************************************************
239 * DisplayImage: load and display an image (ok ?)
240 *******************************************************************************
241 * Try to load an image identified by it's filename and displays it as a still
242 * image using interface video heap.
243 *******************************************************************************/
244 static int DisplayImage( int i_argc, intf_arg_t *p_argv )
247 return( INTF_NO_ERROR );
250 /*******************************************************************************
251 * Help: list all available commands (ok ?)
252 *******************************************************************************
253 * This function print a list of available commands
254 *******************************************************************************/
255 static int Help( int i_argc, intf_arg_t *p_argv )
257 int i_index; /* command index */
259 /* If called with an argument: look for the command and display it's help */
262 for( i_index = 0; control_command[i_index].psz_name
263 && strcmp( control_command[i_index].psz_name, p_argv[1].psz_str );
268 /* Command has been found in list */
269 if( control_command[i_index].psz_name )
271 intf_IntfMsg( control_command[i_index].psz_usage );
272 intf_IntfMsg( control_command[i_index].psz_help );
274 /* Command is unknown */
277 intf_IntfMsg("help: don't know command `%s'", p_argv[1].psz_str);
278 return( INTF_OTHER_ERROR );
281 /* If called without argument: print all commands help field */
284 for( i_index = 0; control_command[i_index].psz_name; i_index++ )
286 intf_IntfMsg( "%s: %s", control_command[i_index].psz_name,
287 control_command[i_index].psz_summary );
291 return( INTF_NO_ERROR );
294 /******************************************************************************
295 * PlayAudio: play an audio file (ok ?)
296 ******************************************************************************
297 * Play a raw audio file from a file, at a given rate.
298 ******************************************************************************/
299 static int PlayAudio( int i_argc, intf_arg_t *p_argv )
301 char *psz_file; /* name of the audio raw file (s16) */
302 int i_fd; /* file descriptor of the audio file that is to be loaded */
303 aout_fifo_t fifo; /* fifo stores the informations about the file */
304 struct stat stat_buffer; /* needed to find out the size of psz_file */
305 int i_arg; /* argument index */
307 if ( !p_program_data->cfg.b_audio ) /* audio is disabled */
309 intf_IntfMsg("play-audio error: audio is disabled");
310 return( INTF_NO_ERROR );
313 /* Set default configuration */
314 fifo.b_stereo = AOUT_DEFAULT_STEREO;
315 fifo.l_rate = AOUT_DEFAULT_RATE;
317 /* The stereo and rate parameters are essential ! */
318 /* Parse parameters - see command list above */
319 for ( i_arg = 1; i_arg < i_argc; i_arg++ )
321 switch( p_argv[i_arg].i_index )
324 fifo.b_stereo = p_argv[i_arg].i_num;
327 fifo.l_rate = p_argv[i_arg].i_num;
329 case 2: /* filename */
330 psz_file = p_argv[i_arg].psz_str;
335 /* Setting up the type of the fifo */
336 switch ( fifo.b_stereo )
339 fifo.i_type = AOUT_INTF_MONO_FIFO;
343 fifo.i_type = AOUT_INTF_STEREO_FIFO;
347 intf_IntfMsg("play-audio error: stereo must be 0 or 1");
348 return( INTF_OTHER_ERROR );
352 i_fd = open( psz_file, O_RDONLY );
353 if ( i_fd < 0 ) /* error */
355 intf_IntfMsg("play-audio error: can't open `%s'", psz_file);
356 return( INTF_OTHER_ERROR );
359 /* Get file size to calculate number of audio units */
360 fstat( i_fd, &stat_buffer );
361 fifo.l_units = ( long )( stat_buffer.st_size / (sizeof(s16) << fifo.b_stereo) );
363 /* Allocate memory, read file and close it */
364 if ( (fifo.buffer = malloc(sizeof(s16)*(fifo.l_units << fifo.b_stereo))) == NULL ) /* !! */
366 intf_IntfMsg("play-audio error: not enough memory to read `%s'", psz_file );
367 close( i_fd ); /* close file */
368 return( INTF_OTHER_ERROR );
370 if ( read(i_fd, fifo.buffer, sizeof(s16)*(fifo.l_units << fifo.b_stereo))
371 != sizeof(s16)*(fifo.l_units << fifo.b_stereo) )
373 intf_IntfMsg("play-audio error: can't read %s", psz_file);
376 return( INTF_OTHER_ERROR );
380 /* Now we can work out how many output units we can compute with the fifo */
381 fifo.l_units = (long)(((s64)fifo.l_units*(s64)p_program_data->aout_thread.dsp.l_rate)/(s64)fifo.l_rate);
383 /* Create the fifo */
384 if ( aout_CreateFifo(&p_program_data->aout_thread, &fifo) == NULL )
386 intf_IntfMsg("play-audio error: can't create audio fifo");
388 return( INTF_OTHER_ERROR );
391 return( INTF_NO_ERROR );
394 /*******************************************************************************
395 * PlayVideo: play a video sequence from a file
396 *******************************************************************************
398 *******************************************************************************/
399 static int PlayVideo( int i_argc, intf_arg_t *p_argv )
402 return( INTF_NO_ERROR );
405 /*******************************************************************************
406 * Quit: quit program (ok ?)
407 *******************************************************************************
408 * This function set `die' flag of interface, asking the program to terminate.
409 *******************************************************************************/
410 static int Quit( int i_argc, intf_arg_t *p_argv )
412 p_program_data->intf_thread.b_die = 1;
413 return( INTF_NO_ERROR );
417 /******************************************************************************
419 ******************************************************************************
421 ******************************************************************************/
422 static int SelectPID( int i_argc, intf_arg_t *p_argv )
427 /* Parse parameters - see command list above */
428 for ( i_arg = 1; i_arg < i_argc; i_arg++ )
430 switch( p_argv[i_arg].i_index )
433 i_input = p_argv[i_arg].i_num;
436 i_pid = p_argv[i_arg].i_num;
442 /* Find to which input this command is destinated */
443 if(i_input < INPUT_MAX_THREADS )
445 if( p_program_data->intf_thread.pp_input[i_input] )
447 intf_IntfMsg( "Adding PID %d to input %d\n", i_pid, i_input );
448 input_AddPgrmElem( p_program_data->intf_thread.pp_input[i_input],
450 return( INTF_NO_ERROR );
454 /* No such input was created */
455 intf_IntfMsg("No such input thread is currently running: %d\n", i_input);
456 return( INTF_OTHER_ERROR );
460 /******************************************************************************
461 * SpawnInput: spawn an input thread (ok ?)
462 ******************************************************************************
463 * Spawn an input thread with the correct p_cfg parameters.
464 ******************************************************************************/
465 static int SpawnInput( int i_argc, intf_arg_t *p_argv )
471 bzero( &cfg, sizeof( cfg ) );
473 /* Parse parameters - see command list above */
474 for ( i_arg = 1; i_arg < i_argc; i_arg++ )
476 switch( p_argv[i_arg].i_index )
479 cfg.i_method = p_argv[i_arg].i_num;
481 case 1: /* filename */
482 cfg.psz_filename = p_argv[i_arg].psz_str;
484 case 2: /* hostname */
485 cfg.psz_hostname = p_argv[i_arg].psz_str;
488 cfg.psz_ip = p_argv[i_arg].psz_str;
491 cfg.i_port = p_argv[i_arg].i_num;
494 cfg.i_vlan = p_argv[i_arg].i_num;
499 /* Setting i_properties to indicate which parameters are set. */
502 cfg.i_properties |= INPUT_CFG_METHOD;
504 if( cfg.psz_filename )
506 cfg.i_properties |= INPUT_CFG_FILENAME;
508 if( cfg.psz_hostname )
510 cfg.i_properties |= INPUT_CFG_HOSTNAME;
514 cfg.i_properties |= INPUT_CFG_IP;
518 cfg.i_properties |= INPUT_CFG_PORT;
522 cfg.i_properties |= INPUT_CFG_VLAN;
525 /* Default settings for the decoder threads */
526 cfg.p_aout = p_program_data->intf_thread.p_aout;
528 /* Create the input thread */
529 if( intf_CreateInputThread( &p_program_data->intf_thread, &cfg ) == -1)
531 return( INTF_OTHER_ERROR );
534 return( INTF_NO_ERROR );
537 /*******************************************************************************
538 * Test: test function
539 *******************************************************************************
540 * This function is provided to test new functions in the program. Fell free
542 * This function is only defined in DEBUG mode.
543 *******************************************************************************/
545 static int Test( int i_argc, intf_arg_t *p_argv )
551 i_thread = intf_CreateVoutThread( &p_program_data->intf_thread, NULL, -1, -1);
552 intf_IntfMsg("return value: %d", i_thread );
556 i_thread = p_argv[1].i_num;
557 intf_DestroyVoutThread( &p_program_data->intf_thread, i_thread );
560 return( INTF_NO_ERROR );
564 /*******************************************************************************
565 * Vlan: vlan operations
566 *******************************************************************************
567 * This function performs various vlan operations.
568 *******************************************************************************/
569 static int Vlan( int i_argc, intf_arg_t *p_argv )
571 int i_command; /* command argument number */
573 /* Do not try anything if vlans are desactivated */
574 if( !p_program_data->cfg.b_vlans )
576 intf_IntfMsg("vlans are desactivated");
577 return( INTF_OTHER_ERROR );
580 /* Look for command in list of arguments - this argument is mandatory and
581 * imposed by the calling function */
582 for( i_command = 1; p_argv[i_command].i_index == 1; i_command++ )
587 /* Command is 'synchro' */
588 if( !strcmp(p_argv[i_command].psz_str, "synchro") )
590 input_VlanSynchronize();
592 /* Command is 'request' */
593 else if( !strcmp(p_argv[i_command].psz_str, "request") )
597 /* Command is 'join' */
598 else if( !strcmp(p_argv[i_command].psz_str, "join") )
602 /* Command is 'leave' */
603 else if( !strcmp(p_argv[i_command].psz_str, "leave") )
607 /* Command is unknown */
610 intf_IntfMsg("vlan error: unknown command %s", p_argv[i_command].psz_str );
611 return( INTF_USAGE_ERROR );
614 return( INTF_NO_ERROR );
618 /*******************************************************************************
620 *******************************************************************************
621 * This function is provided to display PSI tables.
622 *******************************************************************************/
623 static int Psi( int i_argc, intf_arg_t *p_argv )
625 int i_index = p_argv[1].i_num;
627 if(i_index < INPUT_MAX_THREADS )
629 if(p_program_data->intf_thread.pp_input[i_index])
631 /* Read the Psi table for that thread */
632 intf_IntfMsg("Reading PSI table for input %d\n", i_index);
633 input_PsiRead(p_program_data->intf_thread.pp_input[i_index]);
634 return( INTF_NO_ERROR );
638 /* No such input was created */
639 intf_IntfMsg("No such input thread is currently running: %d\n", i_index);
641 return( INTF_OTHER_ERROR );