1 /*****************************************************************************
2 * intf_ctrl.c: interface commands access to control functions
3 * Library of functions common to all interfaces, allowing access to various
4 * structures and settings. Interfaces should only use those functions
5 * to read or write informations from other threads.
6 * A control function must be declared in the `local prototypes' section (it's
7 * type is fixed), and copied into the control_command array. Functions should
8 * be listed in alphabetical order, so when `help' is called they are also
9 * displayed in this order.
10 * A control function can use any function of the program, but should respect
11 * two points: first, it should not block, since if it does so, the whole
12 * interface thread will hang and in particular miscelannous interface events
13 * won't be handled. Secondly, it should send it's output messages exclusively
14 * with intf_IntfMsg() function, except particularly critical messages which
15 * can use over intf_*Msg() functions.
16 * Control functions should return 0 (INTF_NO_ERROR) on success, or one of the
17 * error codes defined in command.h. Custom error codes are allowed, but should
19 * More informations about parameters stand in `list of commands' section.
20 *****************************************************************************
21 * Copyright (C) 1999, 2000 VideoLAN
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 2 of the License, or
28 * (at your option) any later version.
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
35 * You should have received a copy of the GNU General Public License
36 * along with this program; if not, write to the Free Software
37 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
38 *****************************************************************************/
40 /*****************************************************************************
42 *****************************************************************************/
45 #include <sys/types.h> /* on BSD, uio.h needs types.h */
46 #include <sys/stat.h> /* on BSD, fstat() needs stat.h */
47 #include <sys/uio.h> /* "input.h" */
48 #include <stdio.h> /* fprintf() */
49 #include <stdlib.h> /* malloc(), free() */
50 #include <unistd.h> /* close(), read() */
51 #include <fcntl.h> /* open() */
62 #include "stream_control.h"
63 #include "input_ext-intf.h"
64 #include "audio_output.h"
66 #include "interface.h"
72 static int Demo ( int i_argc, intf_arg_t *p_argv );
73 static int DisplayImage ( int i_argc, intf_arg_t *p_argv );
74 static int Exec ( int i_argc, intf_arg_t *p_argv );
75 static int Help ( int i_argc, intf_arg_t *p_argv );
76 static int PlayAudio ( int i_argc, intf_arg_t *p_argv );
77 static int PlayVideo ( int i_argc, intf_arg_t *p_argv );
78 static int Quit ( int i_argc, intf_arg_t *p_argv );
79 static int SelectPID ( int i_argc, intf_arg_t *p_argv );
80 static int SpawnInput ( int i_argc, intf_arg_t *p_argv );
82 static int Test ( int i_argc, intf_arg_t *p_argv );
84 static int Vlan ( int i_argc, intf_arg_t *p_argv );
85 static int Psi ( int i_argc, intf_arg_t *p_argv );
89 * This list is used by intf_ExecCommand function to find functions to
90 * execute and prepare its arguments. It is terminated by an element which name
91 * is a null pointer. intf_command_t is defined in command.h.
93 * Here is a description of a command description elements:
94 * name is the name of the function, as it should be typed on command line,
95 * function is a pointer to the control function,
96 * format is an argument descriptor (see below),
97 * summary is a text string displayed in regard of the command name when `help'
98 * is called without parameters, and whith usage on syntax error,
99 * usage is a short syntax indicator displayed with summary when the command
100 * causes a syntax error,
101 * help is a complete help about the command, displayed when `help' is called with
102 * the command name as parameter.
104 * Format string is a list of ' ' separated strings, which have following
109 * ? optionnal argument
110 * * argument can be repeated
111 * name= named argument
112 * Example: "channel=i? s*? i " means that any number of string arguments,
113 * followed by a single mandatory integer argument are waited. A named argument,
114 * which name is `channel' and must have an integer value can be optionnaly
115 * specified at beginning. The last space is mandatory if there is at least one
116 * element, since it acts as an item terminator.
117 * Named arguments MUST be at the beginning of the format string, and in
118 * alphabetic order, but their order on command line has no importance.
119 * The format string can't have more than INTF_MAX_ARGS elements.
121 const intf_command_t control_command[] =
123 { "demo", Demo, /* demo */
125 /* summary: */ "program demonstration",
127 /* help: */ "Start program capabilities demonstration." },
128 { "display", DisplayImage, /* display */
130 /* summary: */ "load and display an image",
131 /* usage: */ "display <file>",
132 /* help: */ "Load and display an image. Image format is automatically "\
133 "identified from file name extension." },
134 { "exec", Exec, /* exec */
136 /* summary: */ "execute a script file",
137 /* usage: */ "exec <file>",
138 /* help: */ "Load an execute a script." },
139 { "exit", Quit, /* exit (quit alias) */
141 /* summary: */ "quit program",
143 /* help: */ "see `quit'." },
144 { "help", Help, /* help */
146 /* summary: */ "list all functions or print help about a specific function",
147 /* usage: */ "help [command]",
148 /* help: */ "If called without argument, list all available " \
149 " functions.\nIf a command name is provided as argument, displays a short "\
150 "inline help about the command.\n" },
151 { "play-audio", PlayAudio, /* play-audio */
152 /* format: */ "channels=i? rate=i? s ",
153 /* summary: */ "play an audio file",
154 /* usage: */ "play-audio [channels=1/2] [rate=r] <file>",
155 /* help: */ "Load and play an audio file." },
156 { "play-video", PlayVideo, /* play-video */
158 /* summary: */ "play a video (.vlp) file",
159 /* usage: */ "play-video <file>",
160 /* help: */ "Load and play a video file." },
161 { "quit", Quit, /* quit */
163 /* summary: */ "quit program",
165 /* help: */ "Terminates the program execution... There is not much to"\
167 { "select-pid", SelectPID, /* select-pid */
168 /* format: */ "i i ",
169 /* summary: */ "spawn a decoder thread for a specified PID",
170 /* summary: */ "select-pid <input> <pid>",
171 /* help: */ "Spawn a decoder thread for <pid>. The stream will be" \
172 " received by <input>." },
173 { "spawn-input", SpawnInput, /* spawn-input */
174 /* format: */ "method=i? filename=s? hostname=s? ip=s? port=i? vlan=i?",
175 /* summary: */ "spawn an input thread",
176 /* summary: */ "spawn-input [method=<method>]\n" \
177 "[filename=<file>|hostname=<hostname>|ip=<ip>]\n" \
178 "[port=<port>] [vlan=<vlan>]",
179 /* help: */ "Spawn an input thread. Method is 10, 20, 21, 22, 32, "\
180 "hostname is the fully-qualified domain name, ip is a dotted-decimal address." },
182 { "test", Test, /* test */
184 /* summary: */ "crazy developper's test",
185 /* usage: */ "depends on the last coder :-)",
186 /* help: */ "`test' works only in DEBUG mode, and is provide for " \
187 "developpers as an easy way to test part of their code. If you don't know "\
188 "what it should do, just try !" },
191 /* format: */ "intf=s? s i? ",
192 /* summary: */ "vlan operations",
193 /* usage: */ "vlan synchro\n" \
194 "vlan [intf=<interface>] request\n" \
195 "vlan [intf=<interface>] join <vlan>\n" \
196 "vlan [intf=<interface>] leave",
197 /* help: */ "Perform various operations on vlans. 'synchro' resynchronize " \
198 "with the server. 'request' ask which is the current vlan (for the default "\
199 "interface or for a given one). 'join' and 'leave' try to change vlan." },
202 /* summary: */ "Dump PSI tables",
203 /* usage: */ "psi <input thread index>",
204 /* help: */ "Display the PSI tables on the console. Warning: this is debug" \
205 "command, it can leads to pb since locks are not taken yet" },
206 { 0, 0, 0, 0, 0 } /* array terminator */
209 /* following functions are local */
211 /*****************************************************************************
213 *****************************************************************************
214 * This function is provided to display a demo of program possibilities.
215 *****************************************************************************/
216 static int Demo( int i_argc, intf_arg_t *p_argv )
218 intf_IntfMsg( COPYRIGHT_MESSAGE );
220 return( INTF_NO_ERROR );
223 /*****************************************************************************
224 * Exec: execute a script
225 *****************************************************************************
226 * This function load and execute a script.
227 *****************************************************************************/
228 static int Exec( int i_argc, intf_arg_t *p_argv )
230 int i_err; /* error code */
232 i_err = intf_ExecScript( p_argv[1].psz_str );
233 return( i_err ? INTF_OTHER_ERROR : INTF_NO_ERROR );
236 /*****************************************************************************
237 * DisplayImage: load and display an image (ok ?)
238 *****************************************************************************
239 * Try to load an image identified by it's filename and displays it as a still
240 * image using interface video heap.
241 *****************************************************************************/
242 static int DisplayImage( int i_argc, intf_arg_t *p_argv )
245 return( INTF_NO_ERROR );
248 /*****************************************************************************
249 * Help: list all available commands (ok ?)
250 *****************************************************************************
251 * This function print a list of available commands
252 *****************************************************************************/
253 static int Help( int i_argc, intf_arg_t *p_argv )
255 int i_index; /* command index */
257 /* If called with an argument: look for the command and display it's help */
260 fprintf( stderr, "maxx debug: coin\n" );
261 for( i_index = 0; control_command[i_index].psz_name
262 && strcmp( control_command[i_index].psz_name, p_argv[1].psz_str );
267 fprintf( stderr, "maxx debug: meuh\n" );
268 /* Command has been found in list */
269 if( control_command[i_index].psz_name )
271 fprintf( stderr, "maxx debug: meow\n" );
272 intf_IntfMsg( control_command[i_index].psz_usage );
273 fprintf( stderr, "maxx debug: blah\n" );
274 intf_IntfMsg( control_command[i_index].psz_help );
275 fprintf( stderr, "maxx debug: blih\n" );
277 /* Command is unknown */
280 intf_IntfMsg("help: don't know command `%s'", p_argv[1].psz_str);
281 return( INTF_OTHER_ERROR );
284 /* If called without argument: print all commands help field */
287 for( i_index = 0; control_command[i_index].psz_name; i_index++ )
289 intf_IntfMsg( "%s: %s", control_command[i_index].psz_name,
290 control_command[i_index].psz_summary );
294 return( INTF_NO_ERROR );
297 /*****************************************************************************
298 * PlayAudio: play an audio file (ok ?)
299 *****************************************************************************
300 * Play a raw audio file from a file, at a given rate.
301 *****************************************************************************/
302 static int PlayAudio( int i_argc, intf_arg_t *p_argv )
304 char * psz_file = NULL; /* name of the audio raw file (s16) */
305 int i_fd; /* file descriptor of the audio file that is to be loaded */
306 aout_fifo_t fifo; /* fifo stores the informations about the file */
307 struct stat stat_buffer; /* needed to find out the size of psz_file */
308 int i_arg; /* argument index */
310 if ( !p_main->b_audio ) /* audio is disabled */
312 intf_IntfMsg("play-audio error: audio is disabled");
313 return( INTF_NO_ERROR );
316 /* Set default configuration */
317 fifo.i_channels = 1 + ( fifo.b_stereo = AOUT_STEREO_DEFAULT );
318 fifo.l_rate = AOUT_RATE_DEFAULT;
320 /* The channels and rate parameters are essential ! */
321 /* Parse parameters - see command list above */
322 for ( i_arg = 1; i_arg < i_argc; i_arg++ )
324 switch( p_argv[i_arg].i_index )
326 case 0: /* channels */
327 fifo.i_channels = p_argv[i_arg].i_num;
330 fifo.l_rate = p_argv[i_arg].i_num;
332 case 2: /* filename */
333 psz_file = p_argv[i_arg].psz_str;
338 /* Setting up the type of the fifo */
339 switch ( fifo.i_channels )
342 fifo.i_type = AOUT_INTF_MONO_FIFO;
346 fifo.i_type = AOUT_INTF_STEREO_FIFO;
350 intf_IntfMsg("play-audio error: channels must be 1 or 2");
351 return( INTF_OTHER_ERROR );
355 i_fd = open( psz_file, O_RDONLY );
356 if ( i_fd < 0 ) /* error */
358 intf_IntfMsg("play-audio error: can't open `%s'", psz_file);
359 return( INTF_OTHER_ERROR );
362 /* Get file size to calculate number of audio units */
363 fstat( i_fd, &stat_buffer );
364 fifo.l_units = ( long )( stat_buffer.st_size / (sizeof(s16) << fifo.b_stereo) );
366 /* Allocate memory, read file and close it */
367 if ( (fifo.buffer = malloc(sizeof(s16)*(fifo.l_units << fifo.b_stereo))) == NULL ) /* !! */
369 intf_IntfMsg("play-audio error: not enough memory to read `%s'", psz_file );
370 close( i_fd ); /* close file */
371 return( INTF_OTHER_ERROR );
373 if ( read(i_fd, fifo.buffer, sizeof(s16)*(fifo.l_units << fifo.b_stereo))
374 != sizeof(s16)*(fifo.l_units << fifo.b_stereo) )
376 intf_IntfMsg("play-audio error: can't read %s", psz_file);
379 return( INTF_OTHER_ERROR );
383 /* Now we can work out how many output units we can compute with the fifo */
384 fifo.l_units = (long)(((s64)fifo.l_units*(s64)p_main->p_aout->l_rate)/(s64)fifo.l_rate);
386 /* Create the fifo */
387 if ( aout_CreateFifo(p_main->p_aout, &fifo) == NULL )
389 intf_IntfMsg("play-audio error: can't create audio fifo");
391 return( INTF_OTHER_ERROR );
394 return( INTF_NO_ERROR );
397 /*****************************************************************************
398 * PlayVideo: play a video sequence from a file
399 *****************************************************************************
401 *****************************************************************************/
402 static int PlayVideo( int i_argc, intf_arg_t *p_argv )
405 return( INTF_NO_ERROR );
408 /*****************************************************************************
409 * Quit: quit program (ok ?)
410 *****************************************************************************
411 * This function set `die' flag of interface, asking the program to terminate.
412 *****************************************************************************/
413 static int Quit( int i_argc, intf_arg_t *p_argv )
415 p_main->p_intf->b_die = 1;
416 return( INTF_NO_ERROR );
420 /*****************************************************************************
422 *****************************************************************************
424 *****************************************************************************/
425 static int SelectPID( int i_argc, intf_arg_t *p_argv )
427 int i_input = -1, i_pid = -1;
430 /* Parse parameters - see command list above */
431 for ( i_arg = 1; i_arg < i_argc; i_arg++ )
433 switch( p_argv[i_arg].i_index )
436 /* FIXME: useless ?? */
437 i_input = p_argv[i_arg].i_num;
440 i_pid = p_argv[i_arg].i_num;
446 /* Find to which input this command is destinated */
447 intf_IntfMsg( "Adding PID %d to input %d\n", i_pid, i_input );
448 //XXX?? input_AddPgrmElem( p_main->p_intf->p_x11->p_input,
450 return( INTF_NO_ERROR );
454 /*****************************************************************************
455 * SpawnInput: spawn an input thread (ok ?)
456 *****************************************************************************
457 * Spawn an input thread
458 *****************************************************************************/
459 static int SpawnInput( int i_argc, intf_arg_t *p_argv )
465 int i_method = 0; /* method parameter */
466 char * p_source = NULL; /* source parameter */
467 int i_port = 0; /* port parameter */
468 int i_vlan_id = 0; /* vlan id parameter */
470 /* Parse parameters - see command list above */
471 for ( i_arg = 1; i_arg < i_argc; i_arg++ )
473 switch( p_argv[i_arg].i_index )
476 i_method = p_argv[i_arg].i_num;
478 case 1: /* filename, hostname, ip */
481 p_source = p_argv[i_arg].psz_str;
484 i_port = p_argv[i_arg].i_num;
486 case 5: /* VLAN id */
487 i_vlan_id = p_argv[i_arg].i_num;
492 /* Destroy current input, if any */
493 if( p_main->p_intf->p_input != NULL )
495 input_DestroyThread( p_main->p_intf->p_input, NULL );
498 p_main->p_intf->p_input = input_CreateThread( i_method, p_source, i_port, i_vlan_id,
499 p_main->p_intf->p_vout, p_main->p_aout,
501 return( INTF_NO_ERROR );
505 /*****************************************************************************
506 * Test: test function
507 *****************************************************************************
508 * This function is provided to test new functions in the program. Fell free
510 * This function is only defined in DEBUG mode.
511 *****************************************************************************/
513 static int Test( int i_argc, intf_arg_t *p_argv )
517 /*XXX?? if( i_argc == 1 )
519 i_thread = intf_CreateVoutThread( &p_main->intf_thread, NULL, -1, -1);
520 intf_IntfMsg("return value: %d", i_thread );
524 i_thread = p_argv[1].i_num;
525 //XXX?? intf_DestroyVoutThread( &p_main->intf_thread, i_thread );
528 return( INTF_NO_ERROR );
532 /*****************************************************************************
533 * Vlan: vlan operations
534 *****************************************************************************
535 * This function performs various vlan operations.
536 *****************************************************************************/
537 static int Vlan( int i_argc, intf_arg_t *p_argv )
539 int i_command; /* command argument number */
541 /* Do not try anything if vlans are deactivated */
542 if( !p_main->b_vlans )
544 intf_IntfMsg("vlans are deactivated");
545 return( INTF_OTHER_ERROR );
548 /* Look for command in list of arguments - this argument is mandatory and
549 * imposed by the calling function */
550 for( i_command = 1; p_argv[i_command].i_index == 1; i_command++ )
555 /* Command is 'join' */
556 if( !strcmp(p_argv[i_command].psz_str, "join") )
560 /* Command is 'leave' */
561 else if( !strcmp(p_argv[i_command].psz_str, "leave") )
565 /* Command is unknown */
568 intf_IntfMsg("vlan error: unknown command %s", p_argv[i_command].psz_str );
569 return( INTF_USAGE_ERROR );
572 return( INTF_NO_ERROR );
576 /*****************************************************************************
578 *****************************************************************************
579 * This function is provided to display PSI tables.
580 *****************************************************************************/
581 static int Psi( int i_argc, intf_arg_t *p_argv )
583 int i_index = p_argv[1].i_num;
585 intf_IntfMsg("Reading PSI table for input %d\n", i_index);
586 //XXX?? input_PsiRead(p_main->p_intf->p_x11->p_input );
587 return( INTF_NO_ERROR );