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