main.c 14.6 KB
Newer Older
Michel Kaempf's avatar
Michel Kaempf committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*******************************************************************************
 * main.c: main vlc source
 * (c)1998 VideoLAN
 *******************************************************************************
 * Includes the main() function for vlc. Parses command line, start interface
 * and spawn threads.
 *******************************************************************************/

/*******************************************************************************
 * Preamble
 *******************************************************************************/
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Vincent Seguin's avatar
Vincent Seguin committed
18 19

#include <sys/soundcard.h>                                   /* audio_output.h */
Michel Kaempf's avatar
Michel Kaempf committed
20 21 22 23

#include "config.h"
#include "common.h"
#include "mtime.h"
24
#include "vlc_thread.h"
Michel Kaempf's avatar
Michel Kaempf committed
25
#include "input_vlan.h"
Vincent Seguin's avatar
Vincent Seguin committed
26
#include "intf_msg.h"
Michel Kaempf's avatar
Michel Kaempf committed
27
#include "interface.h"
Vincent Seguin's avatar
Vincent Seguin committed
28 29
#include "audio_output.h"
#include "main.h"
Michel Kaempf's avatar
Michel Kaempf committed
30

Vincent Seguin's avatar
Vincent Seguin committed
31
/*******************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
32 33
 * Command line options constants. If something is changed here, be sure that
 * GetConfiguration and Usage are also changed.
Vincent Seguin's avatar
Vincent Seguin committed
34
 *******************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
35 36 37 38 39 40 41 42 43

/* Long options return values - note that values corresponding to short options
 * chars, and in general any regular char, should be avoided */
#define OPT_NOAUDIO             150
#define OPT_STEREO              151
#define OPT_MONO                152
#define OPT_RATE                153

#define OPT_NOVIDEO             160
Vincent Seguin's avatar
Vincent Seguin committed
44 45 46 47
#define OPT_XDGA                161
#define OPT_XSHM                162
#define OPT_XNOSHM              163
#define OPT_XNODGA              164
Michel Kaempf's avatar
Michel Kaempf committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76

#define OPT_NOVLANS             170
#define OPT_VLAN_SERVER         171
 
/* Long options */
static const struct option longopts[] =
{   
    /*  name,               has_arg,    flag,   val */     

    /* General/common options */
    {   "help",             0,          0,      'h' },          

    /* Audio options */
    {   "noaudio",          0,          0,      OPT_NOAUDIO },       
    {   "stereo",           0,          0,      OPT_STEREO },
    {   "mono",             0,          0,      OPT_MONO },      

    /* Video options */
    {   "novideo",          0,          0,      OPT_NOVIDEO },           

    /* VLAN management options */
    {   "novlans",          0,          0,      OPT_NOVLANS },

    {   0,                  0,          0,      0 }
};

/* Short options */
static const char *psz_shortopts = "h";

Vincent Seguin's avatar
Vincent Seguin committed
77 78 79 80
/*******************************************************************************
 * Global variable program_data - this is the one and only, see main.h
 *******************************************************************************/
main_t *p_main;
Michel Kaempf's avatar
Michel Kaempf committed
81

Vincent Seguin's avatar
Vincent Seguin committed
82
/*******************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
83
 * Local prototypes
Vincent Seguin's avatar
Vincent Seguin committed
84 85 86
 *******************************************************************************/
static void SetDefaultConfiguration ( void );
static int  GetConfiguration        ( int i_argc, char *ppsz_argv[], char *ppsz_env[] );
Michel Kaempf's avatar
Michel Kaempf committed
87
static void Usage                   ( void );
Vincent Seguin's avatar
Vincent Seguin committed
88

Michel Kaempf's avatar
Michel Kaempf committed
89 90 91 92 93 94 95 96
static void InitSignalHandler       ( void );
static void SignalHandler           ( int i_signal );

/*******************************************************************************
 * main: parse command line, start interface and spawn threads
 *******************************************************************************
 * Steps during program execution are:
 *      -configuration parsing and messages interface initialization
Vincent Seguin's avatar
Vincent Seguin committed
97
 *      -openning of audio output device and some global modules
Michel Kaempf's avatar
Michel Kaempf committed
98
 *      -execution of interface, which exit on error or on user request
Vincent Seguin's avatar
Vincent Seguin committed
99
 *      -closing of audio output device and some global modules
Michel Kaempf's avatar
Michel Kaempf committed
100 101 102 103
 * On error, the spawned threads are cancelled, and the openned devices closed.
 *******************************************************************************/
int main( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
{
Vincent Seguin's avatar
Vincent Seguin committed
104 105 106
    main_t  main_data;                        /* root of all data - see main.h */
    p_main = &main_data;                         /* set up the global variable */   

Michel Kaempf's avatar
Michel Kaempf committed
107 108
    /*
     * Read configuration, initialize messages interface and set up program
Vincent Seguin's avatar
Vincent Seguin committed
109 110 111
     */    
    p_main->p_msg = intf_MsgCreate();
    if( !p_main->p_msg )                           /* start messages interface */
Michel Kaempf's avatar
Michel Kaempf committed
112
    {
Vincent Seguin's avatar
Vincent Seguin committed
113
        fprintf(stderr, "critical error: can't initialize messages interface (%s)\n",
Michel Kaempf's avatar
Michel Kaempf committed
114 115 116
                strerror(errno));
        return(errno);
    }
Vincent Seguin's avatar
Vincent Seguin committed
117
    if( GetConfiguration( i_argc, ppsz_argv, ppsz_env ) )/* parse command line */
Michel Kaempf's avatar
Michel Kaempf committed
118
    {
Vincent Seguin's avatar
Vincent Seguin committed
119
        intf_MsgDestroy();
Michel Kaempf's avatar
Michel Kaempf committed
120 121 122 123 124 125 126
        return(errno);
    }
    intf_MsgImm( COPYRIGHT_MESSAGE );                 /* print welcome message */

    /*
     * Initialize shared resources and libraries
     */
Vincent Seguin's avatar
Vincent Seguin committed
127
    if( main_data.b_vlans && input_VlanCreate() )
Michel Kaempf's avatar
Michel Kaempf committed
128 129
    {
        /* On error during vlans initialization, switch of vlans */
Vincent Seguin's avatar
Vincent Seguin committed
130 131
        intf_Msg("Virtual LANs initialization failed : vlans management is desactivated\n");
        main_data.b_vlans = 0;
Michel Kaempf's avatar
Michel Kaempf committed
132 133 134
    }
    
    /*
Vincent Seguin's avatar
Vincent Seguin committed
135
     * Open audio device and start aout thread
Michel Kaempf's avatar
Michel Kaempf committed
136
     */
Vincent Seguin's avatar
Vincent Seguin committed
137 138 139 140 141 142 143 144 145
    if( main_data.b_audio )
    {
        main_data.p_aout = aout_CreateThread( NULL );
	if( main_data.p_aout == NULL )
	{
	    /* On error during audio initialization, switch of audio */
            intf_Msg("Audio initialization failed : audio is desactivated\n");
            main_data.b_audio = 0;
	}
Michel Kaempf's avatar
Michel Kaempf committed
146 147 148 149 150
    }
    
    /*
     * Run interface
     */
Vincent Seguin's avatar
Vincent Seguin committed
151 152 153 154 155 156 157
    main_data.p_intf = intf_Create();
    if( main_data.p_intf != NULL )
    {
	InitSignalHandler();               /* prepare signals for interception */
 	intf_Run( main_data.p_intf );
	intf_Destroy( main_data.p_intf );
    }
Michel Kaempf's avatar
Michel Kaempf committed
158

Michel Kaempf's avatar
Michel Kaempf committed
159
    /*
Michel Kaempf's avatar
Michel Kaempf committed
160 161
     * Close audio device
     */
Vincent Seguin's avatar
Vincent Seguin committed
162
    if( main_data.b_audio )
Michel Kaempf's avatar
Michel Kaempf committed
163
    {
Vincent Seguin's avatar
Vincent Seguin committed
164
        aout_DestroyThread( main_data.p_aout, NULL );
Michel Kaempf's avatar
Michel Kaempf committed
165
    }
Michel Kaempf's avatar
Michel Kaempf committed
166 167 168 169

    /*
     * Free shared resources and libraries
     */
Vincent Seguin's avatar
Vincent Seguin committed
170
    if( main_data.b_vlans )
Michel Kaempf's avatar
Michel Kaempf committed
171
    {        
Vincent Seguin's avatar
Vincent Seguin committed
172
        input_VlanDestroy();    
Michel Kaempf's avatar
Michel Kaempf committed
173 174 175 176 177
    }    

    /*
     * Terminate messages interface and program
     */
Vincent Seguin's avatar
Vincent Seguin committed
178 179
    intf_Msg( "Program terminated.\n" );
    intf_MsgDestroy();
Michel Kaempf's avatar
Michel Kaempf committed
180 181 182
    return( 0 );
}

Vincent Seguin's avatar
Vincent Seguin committed
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
/*******************************************************************************
 * main_GetIntVariable: get the int value of an environment variable
 *******************************************************************************
 * This function is used to read some default parameters in modules.
 *******************************************************************************/
int main_GetIntVariable( char *psz_name, int i_default )
{
    char *psz_env;

    psz_env = getenv( psz_name );
    if( psz_env )
    {
	psz_env = strchr( psz_env, '=' );
	if( psz_env )
	{
	    return( atoi( psz_env + 1) );
	}
    }	
    
    return( i_default );
}

/*******************************************************************************
 * main_GetPszVariable: get the string value of an environment variable
 *******************************************************************************
 * This function is used to read some default parameters in modules.
 *******************************************************************************/
char * main_GetPszVariable( char *psz_name, char *psz_default )
{
    char *psz_env;

    psz_env = getenv( psz_name );
    if( psz_env )
    {
	psz_env = strchr( psz_env, '=' );
	if( psz_env )
	{
	    return( psz_env + 1 );
	}
    }

    return( psz_default );    
}

Michel Kaempf's avatar
Michel Kaempf committed
227 228 229 230 231 232
/* following functions are local */

/*******************************************************************************
 * SetDefaultConfiguration: set default options
 *******************************************************************************
 * This function is called by GetConfiguration before command line is parsed.
Vincent Seguin's avatar
Vincent Seguin committed
233 234 235
 * It sets all the default values required later by the program. At this stage,
 * most structure are not yet allocated, so initialization must be done using
 * environment.
Michel Kaempf's avatar
Michel Kaempf committed
236
 *******************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
237
static void SetDefaultConfiguration( void )
Michel Kaempf's avatar
Michel Kaempf committed
238 239
{
    /*
Vincent Seguin's avatar
Vincent Seguin committed
240
     * All features are activated by default
Michel Kaempf's avatar
Michel Kaempf committed
241
     */
Vincent Seguin's avatar
Vincent Seguin committed
242 243 244
    p_main->b_audio  = 1;
    p_main->b_video  = 1;
    p_main->b_vlans  = 1;
Michel Kaempf's avatar
Michel Kaempf committed
245 246

    /*
Vincent Seguin's avatar
Vincent Seguin committed
247
     * Audio output thread configuration 
Michel Kaempf's avatar
Michel Kaempf committed
248 249
     */

Vincent Seguin's avatar
Vincent Seguin committed
250 251 252 253
    // ?? initialization using structures is no more available, use putenv/getenv
    // instead.

   
Michel Kaempf's avatar
Michel Kaempf committed
254 255 256 257

    /*
     * Video output thread configuration
     */
Vincent Seguin's avatar
Vincent Seguin committed
258
    //    p_data->vout_cfg.i_properties =         0;
Michel Kaempf's avatar
Michel Kaempf committed
259 260

    /* VLAN management */
Vincent Seguin's avatar
Vincent Seguin committed
261
    /*???    p_data->cfg.b_vlans =                   0;    
Michel Kaempf's avatar
Michel Kaempf committed
262 263
    p_data->cfg.psz_input_vlan_server =     VLAN_DEFAULT_SERVER;
    p_data->cfg.i_input_vlan_server_port =  VLAN_DEFAULT_SERVER_PORT;    
Vincent Seguin's avatar
Vincent Seguin committed
264
    */
Michel Kaempf's avatar
Michel Kaempf committed
265 266 267 268 269 270 271
}

/*******************************************************************************
 * GetConfiguration: parse command line
 *******************************************************************************
 * Parse command line and configuration file for configuration. If the inline
 * help is requested, the function Usage() is called and the function returns
Vincent Seguin's avatar
Vincent Seguin committed
272 273 274
 * -1 (causing main() to exit). The messages interface is initialized at this 
 * stage, but most structures are not allocated, so only environment should
 * be used.
Michel Kaempf's avatar
Michel Kaempf committed
275
 *******************************************************************************/
Vincent Seguin's avatar
Vincent Seguin committed
276
static int GetConfiguration( int i_argc, char *ppsz_argv[], char *ppsz_env[] )
Michel Kaempf's avatar
Michel Kaempf committed
277
{
Vincent Seguin's avatar
Vincent Seguin committed
278
    int c, i_opt;
Michel Kaempf's avatar
Michel Kaempf committed
279 280

    /* Set default configuration and copy arguments */
Vincent Seguin's avatar
Vincent Seguin committed
281 282 283 284
    p_main->i_argc    = i_argc;
    p_main->ppsz_argv = ppsz_argv;
    p_main->ppsz_env  = ppsz_env;    
    SetDefaultConfiguration();
Michel Kaempf's avatar
Michel Kaempf committed
285

Vincent Seguin's avatar
Vincent Seguin committed
286
    /* Parse command line options */
Michel Kaempf's avatar
Michel Kaempf committed
287 288 289 290 291 292 293 294 295 296 297 298 299
    opterr = 0;
    while( ( c = getopt_long( i_argc, ppsz_argv, psz_shortopts, longopts, 0 ) ) != EOF )
    {
        switch( c )
        {
        /* General/common options */   
        case 'h':                                                /* -h, --help */
            Usage();
            return( -1 );
            break;

        /* Audio options */
        case OPT_NOAUDIO:                                        /* --noaudio */
Vincent Seguin's avatar
Vincent Seguin committed
300
	    p_main->b_audio = 0;
Michel Kaempf's avatar
Michel Kaempf committed
301
            break;
Vincent Seguin's avatar
Vincent Seguin committed
302 303 304
        case OPT_STEREO:                                          /* --stereo */	    
	    // ?? should be replaced by a putenv
	    //p_main->p_aout->dsp.b_stereo = 1;
Michel Kaempf's avatar
Michel Kaempf committed
305 306
            break;
        case OPT_MONO:                                              /* --mono */
Vincent Seguin's avatar
Vincent Seguin committed
307 308
	    // ?? should be replaced by a putenv
	    //p_main->p_aout->dsp.b_stereo = 0;
Michel Kaempf's avatar
Michel Kaempf committed
309 310 311 312
            break;

        /* Video options */
        case OPT_NOVIDEO:                                         /* --novideo */
Vincent Seguin's avatar
Vincent Seguin committed
313
            p_main->b_video = 0;
Michel Kaempf's avatar
Michel Kaempf committed
314 315 316 317
            break;       

        /* VLAN management options */
        case OPT_NOVLANS:                                         /* --novlans */
Vincent Seguin's avatar
Vincent Seguin committed
318 319
            p_main->b_vlans = 0;
            break;      
Michel Kaempf's avatar
Michel Kaempf committed
320 321 322 323 324 325 326 327 328 329
	    
        /* Internal error: unknown option */
        case '?':                          
        default:
            intf_ErrMsg("intf error: unknown option '%s'\n", ppsz_argv[optind - 1]);
            return( EINVAL );
            break;
        }
    }

Vincent Seguin's avatar
Vincent Seguin committed
330 331 332 333 334
    /* Parse command line parameters - no check is made for these options */
    for( i_opt = optind; i_opt < i_argc; i_opt++ )
    {
	putenv( ppsz_argv[ i_opt ] );
    }
Michel Kaempf's avatar
Michel Kaempf committed
335 336 337 338 339 340 341 342 343 344 345
    return( 0 );
}

/*******************************************************************************
 * Usage: print program usage
 *******************************************************************************
 * Print a short inline help. Message interface is initialized at this stage.
 *******************************************************************************/
static void Usage( void )
{
    intf_Msg(COPYRIGHT_MESSAGE);
Vincent Seguin's avatar
Vincent Seguin committed
346 347 348 349 350 351 352 353
    /* Usage */
    intf_Msg("usage: vlc [options...] [parameters]\n" \
	     "  parameters can be passed using environment variables\n" \
	     "  example: vlan_server=vlan-server.via.ecp.fr:1234\n" \
	     );

    /* Options */
    intf_Msg("Options:" \
Michel Kaempf's avatar
Michel Kaempf committed
354
             "  -h, --help                      print usage\n" \
Vincent Seguin's avatar
Vincent Seguin committed
355
             "  --noaudio                       disable audio\n" \
Michel Kaempf's avatar
Michel Kaempf committed
356 357
             "  --stereo                        enable stereo\n" \
             "  --mono                          disable stereo\n"
Vincent Seguin's avatar
Vincent Seguin committed
358 359
             "  --novideo                       disable video\n" \
             "  --novlans      	                disable vlans\n" \
Michel Kaempf's avatar
Michel Kaempf committed
360 361
             );

Vincent Seguin's avatar
Vincent Seguin committed
362 363 364 365 366 367 368 369 370 371 372 373 374 375
    /* Interface parameters */
    intf_Msg("Interface parameters:\n" \
	     "  " INTF_INIT_SCRIPT_VAR "=<filename>             initialization script\n" \
	     );

    /* Audio parameters */
    intf_Msg("Audio parameters:\n" \
             "  " AOUT_DSP_VAR "=<filename>              dsp device path\n" \
             "  " AOUT_STEREO_VAR "={1|0}                stereo or mono output\n" \
             "  " AOUT_RATE_VAR "=<rate>                 output rate\n" \
	     );

    /* Video parameters */
    intf_Msg("Video parameters:\n" \
376
             "  " VOUT_FB_DEV_VAR "=<filename>           framebuffer device path\n" \
Vincent Seguin's avatar
Vincent Seguin committed
377 378 379 380 381 382
	     ); 

    /* Vlan parameters */
    intf_Msg("VLANs (Virtual Local Aera Networks) parameters:\n" \
	     "  vlan_server=<host>[:<port>]     VLANs server address and port\n" \
	     );
Michel Kaempf's avatar
Michel Kaempf committed
383 384 385 386 387 388 389 390 391 392 393
}

/*******************************************************************************
 * InitSignalHandler: system signal handler initialization
 *******************************************************************************
 * Set the signal handlers. SIGTERM is not intercepted, because we need at
 * at least a method to kill the program when all other methods failed, and 
 * when we don't want to use SIGKILL.
 *******************************************************************************/
static void InitSignalHandler( void )
{
Vincent Seguin's avatar
Vincent Seguin committed
394 395 396 397
    /* Termination signals */
    signal( SIGHUP,  SignalHandler );
    signal( SIGINT,  SignalHandler );
    signal( SIGQUIT, SignalHandler );
Michel Kaempf's avatar
Michel Kaempf committed
398 399 400 401 402
}

/*******************************************************************************
 * SignalHandler: system signal handler
 *******************************************************************************
Vincent Seguin's avatar
Vincent Seguin committed
403 404
 * This function is called when a signal is received by the program. It tries to
 * end the program in a clean way.
Michel Kaempf's avatar
Michel Kaempf committed
405 406 407
 *******************************************************************************/
static void SignalHandler( int i_signal )
{
Vincent Seguin's avatar
Vincent Seguin committed
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
    /* Once a signal has been trapped, the termination sequence will be armed and 
     * following signals will be ignored to avoid sending messages to an interface
     * having been destroyed */
    signal( SIGHUP,  SIG_IGN );
    signal( SIGINT,  SIG_IGN );
    signal( SIGQUIT, SIG_IGN );

    /* Acknowledge the signal received */
    intf_ErrMsgImm("intf: signal %d received\n", i_signal );

    /* Try to terminate everything - this is done by requesting the end of the 
     * interface thread */
    p_main->p_intf->b_die = 1;
}

Michel Kaempf's avatar
Michel Kaempf committed
423 424