]> git.sesse.net Git - vlc/blob - src/interface/main.c
* input.c : Ajout du bool�en b_error et d'une boucle d'erreur pour
[vlc] / src / interface / main.c
1 /*******************************************************************************
2  * main.c: main vlc source
3  * (c)1998 VideoLAN
4  *******************************************************************************
5  * Includes the main() function for vlc. Parses command line, start interface
6  * and spawn threads.
7  *******************************************************************************/
8
9 /*******************************************************************************
10  * Preamble
11  *******************************************************************************/
12 #include <errno.h>
13 #include <getopt.h>
14 #include <pthread.h>
15 #include <signal.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <netinet/in.h>
20 #include <sys/soundcard.h>
21 #include <sys/uio.h>
22 #include <X11/Xlib.h>
23 #include <X11/extensions/XShm.h>
24
25 #include "config.h"
26 #include "common.h"
27 #include "mtime.h"
28 #include "netutils.h"
29 #include "debug.h"
30
31 #include "intf_msg.h"
32
33 #include "input.h"
34 #include "input_vlan.h"
35 #include "input_netlist.h"
36 #include "decoder_fifo.h"
37
38 #include "audio_output.h"
39 #include "audio_decoder.h"
40
41 #include "video.h"
42 #include "video_output.h"
43 #include "video_decoder.h"
44
45 #include "xconsole.h"
46 #include "interface.h"
47
48 #include "pgm_data.h"
49
50
51
52 /*
53  * Command line options constants. If something is changed here, be sure that
54  * GetConfiguration and Usage are also changed.
55  */
56
57 /* Long options return values - note that values corresponding to short options
58  * chars, and in general any regular char, should be avoided */
59 #define OPT_DISPLAY             130
60
61 #define OPT_CONSOLE_DISPLAY     140
62 #define OPT_CONSOLE_GEOMETRY    141
63
64 #define OPT_NOAUDIO             150
65 #define OPT_STEREO              151
66 #define OPT_MONO                152
67 #define OPT_RATE                153
68
69 #define OPT_NOVIDEO             160
70 #define OPT_XSHM                161
71 #define OPT_NOXSHM              162
72
73 #define OPT_NOVLANS             170
74 #define OPT_VLAN_SERVER         171
75  
76 /* Long options */
77 static const struct option longopts[] =
78 {   
79     /*  name,               has_arg,    flag,   val */     
80
81     /* General/common options */
82     {   "help",             0,          0,      'h' },          
83     {   "display",          1,          0,      OPT_DISPLAY },
84
85     /* Interface options */
86     {   "console-display",  1,          0,      OPT_CONSOLE_DISPLAY }, 
87     {   "console-geometry", 1,          0,      OPT_CONSOLE_GEOMETRY },
88
89     /* Audio options */
90     {   "noaudio",          0,          0,      OPT_NOAUDIO },       
91     {   "stereo",           0,          0,      OPT_STEREO },
92     {   "mono",             0,          0,      OPT_MONO },      
93     {   "rate",             0,          0,      OPT_RATE },
94
95     /* Video options */
96     {   "novideo",          0,          0,      OPT_NOVIDEO },           
97     {   "xshm",             0,          0,      OPT_XSHM },
98     {   "noxshm",           0,          0,      OPT_NOXSHM },    
99
100     /* VLAN management options */
101     {   "novlans",          0,          0,      OPT_NOVLANS },
102     {   "vlanserver",       1,          0,      OPT_VLAN_SERVER },                    
103
104     {   0,                  0,          0,      0 }
105 };
106
107 /* Short options */
108 static const char *psz_shortopts = "h";
109
110 /*
111  * Global variable program_data
112  */
113 program_data_t *p_program_data;                              /* see pgm_data.h */
114
115 /*
116  * Local prototypes
117  */
118 static void SetDefaultConfiguration ( program_data_t *p_data );
119 static int  GetConfiguration        ( program_data_t *p_config, int i_argc, char *ppsz_argv[],
120                                       char *ppsz_env[] );
121 static void Usage                   ( void );
122 static long GetIntParam             ( const char *psz_param, long i_min, long i_max, int *pi_err );
123 static void InitSignalHandler       ( void );
124 static void SignalHandler           ( int i_signal );
125
126 /*******************************************************************************
127  * main: parse command line, start interface and spawn threads
128  *******************************************************************************
129  * Steps during program execution are:
130  *      -configuration parsing and messages interface initialization
131  *      -openning of audio output device
132  *      -execution of interface, which exit on error or on user request
133  *      -closing of audio output device
134  * On error, the spawned threads are cancelled, and the openned devices closed.
135  *******************************************************************************
136  * ?? Signal handlers should be restored to default once the interface has
137  * been closed, since they will cause a crash if the message interface is no
138  * more active.
139  *******************************************************************************/
140 int main( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
141 {
142     program_data_t  program_data;         /* root of all data - see pgm_data.h */
143     
144     /*
145      * Read configuration, initialize messages interface and set up program
146      */
147     p_program_data = &program_data;              /* set up the global variable */
148     if( intf_InitMsg( &program_data.intf_msg ) )   /* start messages interface */
149     {
150         fprintf(stderr, "intf critical: can't initialize messages interface (%s)\n",
151                 strerror(errno));
152         return(errno);
153     }
154     if( GetConfiguration( &program_data,                 /* parse command line */
155                           i_argc, ppsz_argv, ppsz_env ) )
156     {
157         intf_TerminateMsg( &program_data.intf_msg );
158         return(errno);
159     }
160     intf_MsgImm( COPYRIGHT_MESSAGE );                 /* print welcome message */
161     InitSignalHandler();                   /* prepare signals for interception */    
162
163     /*
164      * Initialize shared resources and libraries
165      */
166     if( program_data.cfg.b_vlans 
167          && input_VlanMethodInit( &program_data.input_vlan_method, 
168                                   program_data.cfg.psz_input_vlan_server,
169                                   program_data.cfg.i_input_vlan_server_port) )
170     {
171         /* On error during vlans initialization, switch of vlans */
172         intf_Msg("intf: switching off vlans\n");
173         program_data.cfg.b_vlans = 0;
174     }
175     
176     /*
177      * Open audio device
178      */
179     if( program_data.cfg.b_audio )
180     {                                                
181         if( aout_Open( &program_data.aout_thread ) )
182         {
183             /* On error during audio initialization, switch of audio */
184             intf_Msg("intf: switching off audio\n");
185             program_data.cfg.b_audio = 0;
186         }
187         else if( aout_SpawnThread( &program_data.aout_thread ) )
188         {
189             aout_Close( &program_data.aout_thread );
190             input_VlanMethodFree( &program_data.input_vlan_method );            
191             intf_TerminateMsg( &program_data.intf_msg );
192             return( -1 );
193         }
194         program_data.intf_thread.p_aout = &program_data.aout_thread;
195     }
196     
197     /*
198      * Run interface
199      */
200     intf_DbgMsg("intf debug: starting interface\n");
201     intf_Run( &program_data.intf_thread );
202     intf_DbgMsg("intf debug: interface terminated\n");
203
204     /*
205      * Close audio device
206      */
207     if( program_data.cfg.b_audio )
208     {
209         aout_CancelThread( &program_data.aout_thread );
210         aout_Close( &program_data.aout_thread );
211     }
212
213     /*
214      * Free shared resources and libraries
215      */
216     if( program_data.cfg.b_vlans )
217     {        
218         input_VlanMethodFree( &program_data.input_vlan_method );    
219     }    
220
221     /*
222      * Terminate messages interface and program
223      */
224     intf_Msg( "program terminated.\n" );
225     intf_TerminateMsg( &program_data.intf_msg );
226     return( 0 );
227 }
228
229 /* following functions are local */
230
231 /*******************************************************************************
232  * SetDefaultConfiguration: set default options
233  *******************************************************************************
234  * This function is called by GetConfiguration before command line is parsed.
235  * It sets all the default values required later by the program. Note that
236  * all properties must be initialized, wether they are command-line dependant
237  * or not.
238  *******************************************************************************/
239 static void SetDefaultConfiguration( program_data_t *p_data )
240 {
241     /*
242      * Audio output thread configuration 
243      */
244     p_data->cfg.b_audio = 1;                 /* audio is activated by default */
245     p_data->aout_thread.dsp.psz_device = AOUT_DEFAULT_DEVICE;
246     /* je rajouterai la détection des formats supportés quand le reste
247      * marchera */
248     p_data->aout_thread.dsp.i_format = AOUT_DEFAULT_FORMAT;
249     p_data->aout_thread.dsp.b_stereo = AOUT_DEFAULT_STEREO;
250     p_data->aout_thread.dsp.l_rate = AOUT_DEFAULT_RATE;
251
252     /*
253      * Interface thread configuration
254      */
255     /* X11 console */
256     p_data->intf_thread.xconsole.psz_display =  NULL;
257     p_data->intf_thread.xconsole.psz_geometry = INTF_XCONSOLE_GEOMETRY;
258
259     /* --- ?? following are ok */
260
261     /*
262      * Video output thread configuration
263      */
264     p_data->cfg.b_video =                   1;    
265     p_data->vout_cfg.i_properties =         0;
266
267     /* VLAN management */
268     p_data->cfg.b_vlans =                   1;    
269     p_data->cfg.psz_input_vlan_server =     VLAN_DEFAULT_SERVER;
270     p_data->cfg.i_input_vlan_server_port =  VLAN_DEFAULT_SERVER_PORT;    
271 }
272
273 /*******************************************************************************
274  * GetConfiguration: parse command line
275  *******************************************************************************
276  * Parse command line and configuration file for configuration. If the inline
277  * help is requested, the function Usage() is called and the function returns
278  * -1 (causing main() to exit). Note than messages interface is initialized at
279  * this stage.
280  *******************************************************************************/
281 static int GetConfiguration( program_data_t *p_data, int i_argc, 
282                              char *ppsz_argv[], char *ppsz_env[] )
283 {
284     int c, i_err;
285
286     /* Set default configuration and copy arguments */
287     p_data->i_argc = i_argc;
288     p_data->ppsz_argv = ppsz_argv;
289     p_data->ppsz_env = ppsz_env;    
290     SetDefaultConfiguration( p_data );
291
292     /* Parse command line */
293     opterr = 0;
294     while( ( c = getopt_long( i_argc, ppsz_argv, psz_shortopts, longopts, 0 ) ) != EOF )
295     {
296         switch( c )
297         {
298         /* General/common options */   
299         case 'h':                                                /* -h, --help */
300             Usage();
301             return( -1 );
302             break;
303         case OPT_DISPLAY:                                         /* --display */
304             p_data->vout_cfg.psz_display = optarg;
305             p_data->vout_cfg.i_properties |= VIDEO_CFG_DISPLAY;
306             p_data->intf_thread.xconsole.psz_display = optarg;
307             break;
308
309         /* Interface options */
310         case OPT_CONSOLE_DISPLAY:                         /* --console-display */
311             p_data->intf_thread.xconsole.psz_display = optarg;
312             break;
313         case OPT_CONSOLE_GEOMETRY:                       /* --console-geometry */
314             p_data->intf_thread.xconsole.psz_geometry = optarg;
315             break;
316
317         /* Audio options */
318         case OPT_NOAUDIO:                                        /* --noaudio */
319             p_data->cfg.b_audio = 0;
320             break;
321         case OPT_STEREO:                                          /* --stereo */
322             p_data->aout_thread.dsp.b_stereo = 1;
323             break;
324         case OPT_MONO:                                              /* --mono */
325             p_data->aout_thread.dsp.b_stereo = 0;
326             break;
327         case OPT_RATE:                                              /* --rate */
328             p_data->aout_thread.dsp.l_rate = GetIntParam(optarg, AOUT_MIN_RATE, AOUT_MAX_RATE, &i_err );
329             if( i_err )
330             {
331                 return( EINVAL );
332             }
333             break;
334
335         /* Video options */
336         case OPT_NOVIDEO:                                         /* --novideo */
337             p_data->cfg.b_video = 0;
338             break;       
339         case OPT_XSHM:                                               /* --xshm */
340             p_data->vout_cfg.b_shm_ext = 1;
341             p_data->vout_cfg.i_properties |= VIDEO_CFG_SHM_EXT;
342             break;
343         case OPT_NOXSHM:                                           /* --noxshm */
344             p_data->vout_cfg.b_shm_ext = 0;
345             p_data->vout_cfg.i_properties |= VIDEO_CFG_SHM_EXT;
346             break;
347
348         /* VLAN management options */
349         case OPT_NOVLANS:                                         /* --novlans */
350             p_data->cfg.b_vlans = 0;
351             break;
352         case  OPT_VLAN_SERVER:                                 /* --vlanserver */
353             p_data->cfg.i_input_vlan_server_port = ServerPort( optarg );
354             p_data->cfg.psz_input_vlan_server = optarg;
355             break;
356             
357         /* Internal error: unknown option */
358         case '?':                          
359         default:
360             intf_ErrMsg("intf error: unknown option '%s'\n", ppsz_argv[optind - 1]);
361             return( EINVAL );
362             break;
363         }
364     }
365
366     return( 0 );
367 }
368
369 /*******************************************************************************
370  * Usage: print program usage
371  *******************************************************************************
372  * Print a short inline help. Message interface is initialized at this stage.
373  *******************************************************************************/
374 static void Usage( void )
375 {
376     intf_Msg(COPYRIGHT_MESSAGE);
377     /* General options */
378     intf_Msg("usage: vlc [options...]\n" \
379              "  -h, --help                      print usage\n" \
380              );
381     /* Audio options */
382     intf_Msg("  --noaudio                       disable audio\n" \
383              "  --stereo                        enable stereo\n" \
384              "  --mono                          disable stereo\n"
385              "  --rate <rate>                   audio output rate (kHz)\n" \
386              );
387     /* Video options */
388     intf_Msg("  --novideo                       disable video\n" \
389              "  --xshm, --noxshm                enable/disable use of XShm extension\n" \
390              "  -d, --display <display>         set display name\n" \
391              );
392
393     /* VLAN management options */
394     intf_Msg("  --novlans                               disable vlans\n" \
395              "  --vlanserver <server[:port]>    set vlan server address\n" \
396              );
397 }
398
399 /*******************************************************************************
400  * GetIntParam: convert a string to an integer
401  *******************************************************************************
402  * This function convert a string to an integer, check range of the value
403  * and that there is no error during convertion. pi_err is a pointer to an
404  * error flag, which contains non 0 on error. This function prints its own
405  * error messages.
406  *******************************************************************************/
407 static long GetIntParam( const char *psz_param, long i_min, long i_max, int *pi_err )
408 {
409     char *psz_endptr;
410     long int i_value;
411
412     i_value = strtol( psz_param, &psz_endptr, 0 );
413     if( (psz_param[0] == '\0') && (*psz_endptr != '\0') )  /* conversion error */
414     {
415         intf_ErrMsg("intf error: conversion error ('%s' should be an integer between %ld and %ld)\n",
416                     psz_param, i_min, i_max );
417         *pi_err = EINVAL;
418         return( 0 );
419     }
420     if( (i_value < i_min) || (i_value > i_max) )                /* range error */
421     {
422         intf_ErrMsg("intf error: range error ('%s' should be an integer between %ld and %ld)\n",
423                     psz_param, i_min, i_max );
424         *pi_err = EINVAL;
425         return( 0 );
426     }
427     *pi_err = 0;
428     return( i_value );
429 }
430 /*******************************************************************************
431  * InitSignalHandler: system signal handler initialization
432  *******************************************************************************
433  * Set the signal handlers. SIGTERM is not intercepted, because we need at
434  * at least a method to kill the program when all other methods failed, and 
435  * when we don't want to use SIGKILL.
436  *******************************************************************************/
437 static void InitSignalHandler( void )
438 {
439   /* Termination signals */
440   signal( SIGHUP, SignalHandler );
441   signal( SIGINT, SignalHandler );
442   signal( SIGQUIT, SignalHandler );
443 }
444
445 /*******************************************************************************
446  * SignalHandler: system signal handler
447  *******************************************************************************
448  * This function is called when a signal is received by the program. It ignores
449  * it or tries to terminate cleanly.
450  *******************************************************************************/
451 static void SignalHandler( int i_signal )
452 {
453   /* Once a signal has been trapped, the signal handler needs to be re-armed on
454    * linux systems */
455   signal( i_signal, SignalHandler );
456
457   /* Acknowledge the signal received */
458   intf_ErrMsgImm("intf: signal %d received\n", i_signal );
459
460   /* Try to terminate everything */
461   /* ?? this probably needs to be changed */
462   p_program_data->intf_thread.b_die = 1;
463 }