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