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