]> git.sesse.net Git - vlc/blob - src/interface/intf_ctrl.c
f8dfa96b11c00e9ca6197a864406b5452bdd84dd
[vlc] / src / interface / intf_ctrl.c
1 /*****************************************************************************
2  * intf_ctrl.c: interface commands access to control functions
3  * (c)1999 VideoLAN
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
20  * be positive.
21  * More informations about parameters stand in `list of commands' section.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include "vlc.h"
28 #include <sys/stat.h>
29
30 /*
31  * Local prototypes
32  */
33 static int Demo                 ( int i_argc, intf_arg_t *p_argv );
34 static int DisplayImage         ( int i_argc, intf_arg_t *p_argv );
35 static int Exec                 ( int i_argc, intf_arg_t *p_argv );
36 static int Help                 ( int i_argc, intf_arg_t *p_argv );
37 static int PlayAudio            ( int i_argc, intf_arg_t *p_argv );
38 static int PlayVideo            ( int i_argc, intf_arg_t *p_argv );
39 static int Quit                 ( int i_argc, intf_arg_t *p_argv );
40 static int SelectPID            ( int i_argc, intf_arg_t *p_argv );
41 static int SpawnInput           ( int i_argc, intf_arg_t *p_argv );
42 #ifdef DEBUG
43 static int Test                 ( int i_argc, intf_arg_t *p_argv );
44 #endif
45 static int Vlan                 ( int i_argc, intf_arg_t *p_argv );
46 static int Psi                  ( int i_argc, intf_arg_t *p_argv );
47
48 /*
49  * List of commands.
50  * This list is used by intf_ExecCommand function to find functions to
51  * execute and prepare its arguments. It is terminated by an element  which name
52  * is a null pointer. intf_command_t is defined in command.h.
53  *
54  * Here is a description of a command description elements:
55  *  name is the name of the function, as it should be typed on command line,
56  *  function is a pointer to the control function,
57  *  format is an argument descriptor (see below),
58  *  summary is a text string displayed in regard of the command name when `help'
59  *      is called without parameters, and whith usage on syntax error,
60  *  usage is a short syntax indicator displayed with summary when the command
61  *      causes a syntax error,
62  *  help is a complete help about the command, displayed when `help' is called with
63  *      the command name as parameter.
64  *
65  * Format string is a list of ' ' separated strings, which have following
66  * meanings:
67  *  s       string argument
68  *  i       integer argument
69  *  f       float argument
70  *  ?       optionnal argument
71  *  *       argument can be repeated
72  *  name=   named argument
73  * Example: "channel=i? s*? i " means that any number of string arguments,
74  * followed by a single mandatory integer argument are waited. A named argument,
75  * which name is `channel' and must have an integer value can be optionnaly
76  * specified at beginning. The last space is mandatory if there is at least one
77  * element, since it acts as an item terminator.
78  * Named arguments MUST be at the beginning of the format string, and in
79  * alphabetic order, but their order on command line has no importance.
80  * The format string can't have more than INTF_MAX_ARGS elements.
81  */
82 const intf_command_t control_command[] =
83 {
84   { "demo", Demo,                                                    /* demo */
85     /* format: */   "",
86     /* summary: */  "program demonstration",
87     /* usage: */    "demo",
88     /* help: */     "Start program capabilities demonstration." },
89   { "display", DisplayImage,                                      /* display */
90     /* format: */   "s ",
91     /* summary: */  "load and display an image",
92     /* usage: */    "display <file>",
93     /* help: */     "Load and display an image. Image format is automatically "\
94     "identified from file name extension." },
95   { "exec", Exec,                                                    /* exec */
96     /* format: */   "s ",
97     /* summary: */  "execute a script file",
98     /* usage: */    "exec <file>",
99     /* help: */     "Load an execute a script." },
100   { "exit", Quit,                                       /* exit (quit alias) */
101     /* format: */   "",
102     /* summary: */  "quit program",
103     /* usage: */    "exit",
104     /* help: */     "see `quit'." },
105   { "help", Help,                                                    /* help */
106     /* format: */   "s? ",
107     /* summary: */  "list all functions or print help about a specific function",
108     /* usage: */    "help [command]",
109     /* help: */     "If called without argument, list all available " \
110     " functions.\nIf a command name is provided as argument, displays a short "\
111     "inline help about the command.\n" },
112   { "play-audio", PlayAudio,                                   /* play-audio */
113     /* format: */   "channels=i? rate=i? s ",
114     /* summary: */  "play an audio file",
115     /* usage: */    "play-audio [channels=1/2] [rate=r] <file>",
116     /* help: */     "Load and play an audio file." },
117   { "play-video", PlayVideo,                                      /* play-video */
118     /* format: */   "s ",
119     /* summary: */  "play a video (.vlp) file",
120     /* usage: */    "play-video <file>",
121     /* help: */     "Load and play a video file." },
122   { "quit", Quit,                                                    /* quit */
123     /* format: */   "",
124     /* summary: */  "quit program",
125     /* usage: */    "quit",
126     /* help: */     "Terminates the program execution... There is not much to"\
127     " say about it !" },
128   { "select-pid", SelectPID,                                   /* select-pid */
129     /* format: */   "i i ",
130     /* summary: */  "spawn a decoder thread for a specified PID",
131     /* summary: */  "select-pid <input> <pid>",
132     /* help: */     "Spawn a decoder thread for <pid>. The stream will be" \
133     " received by <input>." },
134   { "spawn-input", SpawnInput,                                /* spawn-input */
135     /* format: */   "method=i? filename=s? hostname=s? ip=s? port=i? vlan=i?",
136     /* summary: */  "spawn an input thread",
137     /* summary: */  "spawn-input [method=<method>]\n" \
138     "[filename=<file>|hostname=<hostname>|ip=<ip>]\n" \
139     "[port=<port>] [vlan=<vlan>]",
140     /* help: */     "Spawn an input thread. Method is 10, 20, 21, 22, 32, "\
141     "hostname is the fully-qualified domain name, ip is a dotted-decimal address." },
142 #ifdef DEBUG
143   { "test", Test,                                                    /* test */
144     /* format: */   "i? ",
145     /* summary: */  "crazy developper's test",
146     /* usage: */    "depends on the last coder :-)",
147     /* help: */     "`test' works only in DEBUG mode, and is provide for " \
148     "developpers as an easy way to test part of their code. If you don't know "\
149     "what it should do, just try !" },
150 #endif
151   { "vlan", Vlan,
152     /* format: */   "intf=s? s i? ",
153     /* summary: */  "vlan operations",
154     /* usage: */    "vlan synchro\n" \
155     "vlan [intf=<interface>] request\n" \
156     "vlan [intf=<interface>] join <vlan>\n" \
157     "vlan [intf=<interface>] leave",
158     /* help: */     "Perform various operations on vlans. 'synchro' resynchronize " \
159     "with the server. 'request' ask which is the current vlan (for the default "\
160     "interface or for a given one). 'join' and 'leave' try to change vlan." },
161   { "psi", Psi,
162     /* format: */   "i ",
163     /* summary: */  "Dump PSI tables",
164     /* usage: */    "psi <input thread index>",
165     /* help: */     "Display the PSI tables on the console. Warning: this is debug" \
166     "command, it can leads to pb since locks are not taken yet" },
167   { 0, 0, 0, 0, 0 }                                      /* array terminator */
168 };
169
170 /* following functions are local */
171
172 /*****************************************************************************
173  * Demo: demo
174  *****************************************************************************
175  * This function is provided to display a demo of program possibilities.
176  *****************************************************************************/
177 static int Demo( int i_argc, intf_arg_t *p_argv )
178 {
179     intf_IntfMsg( COPYRIGHT_MESSAGE );
180
181     return( INTF_NO_ERROR );
182 }
183
184 /*****************************************************************************
185  * Exec: execute a script
186  *****************************************************************************
187  * This function load and execute a script.
188  *****************************************************************************/
189 static int Exec( int i_argc, intf_arg_t *p_argv )
190 {
191     int i_err;                                                 /* error code */
192
193     i_err = intf_ExecScript( p_argv[1].psz_str );
194     return( i_err ? INTF_OTHER_ERROR : INTF_NO_ERROR );
195 }
196
197 /*****************************************************************************
198  * DisplayImage: load and display an image                               (ok ?)
199  *****************************************************************************
200  * Try to load an image identified by it's filename and displays it as a still
201  * image using interface video heap.
202  *****************************************************************************/
203 static int DisplayImage( int i_argc, intf_arg_t *p_argv )
204 {
205     /* ?? */
206     return( INTF_NO_ERROR );
207 }
208
209 /*****************************************************************************
210  * Help: list all available commands                                     (ok ?)
211  *****************************************************************************
212  * This function print a list of available commands
213  *****************************************************************************/
214 static int Help( int i_argc, intf_arg_t *p_argv )
215 {
216     int     i_index;                                        /* command index */
217
218    /* If called with an argument: look for the command and display it's help */
219     if( i_argc == 2 )
220     {
221 fprintf( stderr, "maxx debug: coin\n" );
222         for( i_index = 0; control_command[i_index].psz_name
223                  && strcmp( control_command[i_index].psz_name, p_argv[1].psz_str );
224              i_index++ )
225         {
226             ;
227         }
228 fprintf( stderr, "maxx debug: meuh\n" );
229         /* Command has been found in list */
230         if( control_command[i_index].psz_name )
231         {
232 fprintf( stderr, "maxx debug: meow\n" );
233             intf_IntfMsg( control_command[i_index].psz_usage );
234 fprintf( stderr, "maxx debug: blah\n" );
235             intf_IntfMsg( control_command[i_index].psz_help );
236 fprintf( stderr, "maxx debug: blih\n" );
237         }
238         /* Command is unknown */
239         else
240         {
241             intf_IntfMsg("help: don't know command `%s'", p_argv[1].psz_str);
242             return( INTF_OTHER_ERROR );
243         }
244     }
245     /* If called without argument: print all commands help field */
246     else
247     {
248         for( i_index = 0; control_command[i_index].psz_name; i_index++ )
249         {
250             intf_IntfMsg( "%s: %s",  control_command[i_index].psz_name,
251                           control_command[i_index].psz_summary );
252         }
253     }
254
255     return( INTF_NO_ERROR );
256 }
257
258 /*****************************************************************************
259  * PlayAudio: play an audio file                                         (ok ?)
260  *****************************************************************************
261  * Play a raw audio file from a file, at a given rate.
262  *****************************************************************************/
263 static int PlayAudio( int i_argc, intf_arg_t *p_argv )
264 {
265     char * psz_file = NULL;              /* name of the audio raw file (s16) */
266     int i_fd;      /* file descriptor of the audio file that is to be loaded */
267     aout_fifo_t fifo;         /* fifo stores the informations about the file */
268     struct stat stat_buffer;      /* needed to find out the size of psz_file */
269     int i_arg;                                             /* argument index */
270
271     if ( !p_main->b_audio )                  /* audio is disabled */
272     {
273         intf_IntfMsg("play-audio error: audio is disabled");
274         return( INTF_NO_ERROR );
275     }
276
277     /* Set default configuration */
278     fifo.i_channels = 1 + ( fifo.b_stereo = AOUT_DEFAULT_STEREO );
279     fifo.l_rate = AOUT_DEFAULT_RATE;
280
281     /* The channels and rate parameters are essential ! */
282     /* Parse parameters - see command list above */
283     for ( i_arg = 1; i_arg < i_argc; i_arg++ )
284     {
285         switch( p_argv[i_arg].i_index )
286         {
287         case 0:                                                  /* channels */
288             fifo.i_channels = p_argv[i_arg].i_num;
289             break;
290         case 1:                                                      /* rate */
291             fifo.l_rate = p_argv[i_arg].i_num;
292             break;
293         case 2:                                                  /* filename */
294             psz_file = p_argv[i_arg].psz_str;
295             break;
296         }
297     }
298
299     /* Setting up the type of the fifo */
300     switch ( fifo.i_channels )
301     {
302         case 1:
303             fifo.i_type = AOUT_INTF_MONO_FIFO;
304             break;
305
306         case 2:
307             fifo.i_type = AOUT_INTF_STEREO_FIFO;
308             break;
309
310         default:
311             intf_IntfMsg("play-audio error: channels must be 1 or 2");
312             return( INTF_OTHER_ERROR );
313     }
314
315     /* Open file */
316     i_fd =  open( psz_file, O_RDONLY );
317     if ( i_fd < 0 )                                                 /* error */
318     {
319         intf_IntfMsg("play-audio error: can't open `%s'", psz_file);
320         return( INTF_OTHER_ERROR );
321     }
322
323     /* Get file size to calculate number of audio units */
324     fstat( i_fd, &stat_buffer );
325     fifo.l_units = ( long )( stat_buffer.st_size / (sizeof(s16) << fifo.b_stereo) );
326
327     /* Allocate memory, read file and close it */
328     if ( (fifo.buffer = malloc(sizeof(s16)*(fifo.l_units << fifo.b_stereo))) == NULL ) /* !! */
329     {
330         intf_IntfMsg("play-audio error: not enough memory to read `%s'", psz_file );
331         close( i_fd );                                         /* close file */
332         return( INTF_OTHER_ERROR );
333     }
334     if ( read(i_fd, fifo.buffer, sizeof(s16)*(fifo.l_units << fifo.b_stereo))
335         != sizeof(s16)*(fifo.l_units << fifo.b_stereo) )
336     {
337         intf_IntfMsg("play-audio error: can't read %s", psz_file);
338         free( fifo.buffer );
339         close( i_fd );
340         return( INTF_OTHER_ERROR );
341     }
342     close( i_fd );
343
344     /* Now we can work out how many output units we can compute with the fifo */
345     fifo.l_units = (long)(((s64)fifo.l_units*(s64)p_main->p_aout->l_rate)/(s64)fifo.l_rate);
346
347     /* Create the fifo */
348     if ( aout_CreateFifo(p_main->p_aout, &fifo) == NULL )
349     {
350         intf_IntfMsg("play-audio error: can't create audio fifo");
351         free( fifo.buffer );
352         return( INTF_OTHER_ERROR );
353     }
354
355     return( INTF_NO_ERROR );
356 }
357
358 /*****************************************************************************
359  * PlayVideo: play a video sequence from a file
360  *****************************************************************************
361  * ??
362  *****************************************************************************/
363 static int PlayVideo( int i_argc, intf_arg_t *p_argv )
364 {
365     /* ?? */
366     return( INTF_NO_ERROR );
367 }
368
369 /*****************************************************************************
370  * Quit: quit program                                                    (ok ?)
371  *****************************************************************************
372  * This function set `die' flag of interface, asking the program to terminate.
373  *****************************************************************************/
374 static int Quit( int i_argc, intf_arg_t *p_argv )
375 {
376     p_main->p_intf->b_die = 1;
377     return( INTF_NO_ERROR );
378 }
379
380
381 /*****************************************************************************
382  *
383  *****************************************************************************
384  *
385  *****************************************************************************/
386 static int SelectPID( int i_argc, intf_arg_t *p_argv )
387 {
388     int i_input = -1, i_pid = -1;
389     int i_arg;
390
391     /* Parse parameters - see command list above */
392     for ( i_arg = 1; i_arg < i_argc; i_arg++ )
393     {
394       switch( p_argv[i_arg].i_index )
395       {
396       case 0:
397           // ?? useless
398           i_input = p_argv[i_arg].i_num;
399           break;
400       case 1:
401          i_pid = p_argv[i_arg].i_num;
402         break;
403       }
404     }
405
406
407     /* Find to which input this command is destinated */
408     intf_IntfMsg( "Adding PID %d to input %d\n", i_pid, i_input );
409 //????    input_AddPgrmElem( p_main->p_intf->p_x11->p_input,
410 //????                       i_pid );
411     return( INTF_NO_ERROR );
412 }
413
414
415 /*****************************************************************************
416  * SpawnInput: spawn an input thread                                     (ok ?)
417  *****************************************************************************
418  * Spawn an input thread
419  *****************************************************************************/
420 static int SpawnInput( int i_argc, intf_arg_t *p_argv )
421 {
422     int                 i_arg;
423     int                 i_method = 0;                    /* method parameter */
424     char *              psz_source = NULL;               /* source parameter */
425     int                 i_port = 0;                        /* port parameter */
426     int                 i_vlan = 0;                        /* vlan parameter */
427
428     /* Parse parameters - see command list above */
429     for ( i_arg = 1; i_arg < i_argc; i_arg++ )
430     {
431         switch( p_argv[i_arg].i_index )
432         {
433         case 0:                                                    /* method */
434             i_method = p_argv[i_arg].i_num;
435             break;
436         case 1:                                    /* filename, hostname, ip */
437         case 2:
438         case 3:
439             psz_source = p_argv[i_arg].psz_str;
440             break;
441         case 4:                                                      /* port */
442             i_port = p_argv[i_arg].i_num;
443             break;
444         case 5:                                                      /* VLAN */
445             i_vlan = p_argv[i_arg].i_num;
446             break;
447         }
448     }
449
450     /* Destroy current input, if any */
451     if( p_main->p_intf->p_input != NULL )
452     {
453         input_DestroyThread( p_main->p_intf->p_input, NULL );
454     }
455
456     p_main->p_intf->p_input = input_CreateThread( i_method, psz_source, i_port, i_vlan,
457                                                   p_main->p_intf->p_vout, p_main->p_aout,
458                                                   NULL );
459     return( INTF_NO_ERROR );
460 }
461
462 /*****************************************************************************
463  * Test: test function
464  *****************************************************************************
465  * This function is provided to test new functions in the program. Fell free
466  * to modify !
467  * This function is only defined in DEBUG mode.
468  *****************************************************************************/
469 #ifdef DEBUG
470 static int Test( int i_argc, intf_arg_t *p_argv )
471 {
472     int i_thread;
473
474 /*??    if( i_argc == 1 )
475     {
476         i_thread = intf_CreateVoutThread( &p_main->intf_thread, NULL, -1, -1);
477         intf_IntfMsg("return value: %d", i_thread );
478     }
479     else*/
480     {
481         i_thread = p_argv[1].i_num;
482     //??    intf_DestroyVoutThread( &p_main->intf_thread, i_thread );
483     }
484
485     return( INTF_NO_ERROR );
486 }
487 #endif
488
489 /*****************************************************************************
490  * Vlan: vlan operations
491  *****************************************************************************
492  * This function performs various vlan operations.
493  *****************************************************************************/
494 static int Vlan( int i_argc, intf_arg_t *p_argv  )
495 {
496     int i_command;                                /* command argument number */
497
498     /* Do not try anything if vlans are desactivated */
499     if( !p_main->b_vlans )
500     {
501         intf_IntfMsg("vlans are desactivated");
502         return( INTF_OTHER_ERROR );
503     }
504
505     /* Look for command in list of arguments - this argument is mandatory and
506      * imposed by the calling function */
507     for( i_command = 1; p_argv[i_command].i_index == 1; i_command++ )
508     {
509         ;
510     }
511
512     /* Command is 'join' */
513     if( !strcmp(p_argv[i_command].psz_str, "join") )
514     {
515         /* ?? */
516     }
517     /* Command is 'leave' */
518     else if( !strcmp(p_argv[i_command].psz_str, "leave") )
519     {
520         /* ?? */
521     }
522     /* Command is unknown */
523     else
524     {
525         intf_IntfMsg("vlan error: unknown command %s", p_argv[i_command].psz_str );
526         return( INTF_USAGE_ERROR );
527     }
528
529     return( INTF_NO_ERROR );
530 }
531
532
533 /*****************************************************************************
534  * Psi
535  *****************************************************************************
536  * This function is provided to display PSI tables.
537  *****************************************************************************/
538 static int Psi( int i_argc, intf_arg_t *p_argv )
539 {
540     int i_index = p_argv[1].i_num;
541
542     intf_IntfMsg("Reading PSI table for input %d\n", i_index);
543 //????    input_PsiRead(p_main->p_intf->p_x11->p_input );
544     return( INTF_NO_ERROR );
545 }