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