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