libvlc.c 29.7 KB
Newer Older
1
/*****************************************************************************
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
2
 * libvlc.c: libvlc instances creation and deletion, interfaces handling
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
4
 * Copyright (C) 1998-2008 VLC authors and VideoLAN
zorglub's avatar
zorglub committed
5
 * $Id$
6
7
8
 *
 * Authors: Vincent Seguin <seguin@via.ecp.fr>
 *          Samuel Hocevar <sam@zoy.org>
9
 *          Gildas Bazin <gbazin@videolan.org>
hartman's avatar
hartman committed
10
 *          Derk-Jan Hartman <hartman at videolan dot org>
11
 *          Rémi Denis-Courmont <rem # videolan : org>
12
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
13
14
15
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
16
17
18
19
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
20
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
22
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
23
24
25
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26
27
 *****************************************************************************/

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
28
29
30
/** \file
 * This file contains functions to create and destroy libvlc instances
 */
31
32
33
34

/*****************************************************************************
 * Preamble
 *****************************************************************************/
35
36
37
38
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

39
#include <vlc_common.h>
40
#include "../lib/libvlc_internal.h"
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
41
#include <vlc_input.h>
42

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
43
44
#include "modules/modules.h"
#include "config/configuration.h"
45

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
46
47
48
#include <stdio.h>                                              /* sprintf() */
#include <string.h>
#include <stdlib.h>                                                /* free() */
49

50
#include "config/vlc_getopt.h"
51

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
52
53
54
#ifdef HAVE_LOCALE_H
#   include <locale.h>
#endif
55
56
57
#ifdef HAVE_UNISTD_H
#   include <unistd.h> /* isatty() */
#endif
58

59
#ifdef HAVE_DBUS
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
60
61
62
/* used for one-instance mode */
#   include <dbus/dbus.h>
#endif
63

jetru's avatar
jetru committed
64
65

#include <vlc_media_library.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
66
67
#include <vlc_playlist.h>
#include <vlc_interface.h>
Sam Hocevar's avatar
Sam Hocevar committed
68

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
69
70
#include <vlc_aout.h>
#include "audio_output/aout_internal.h"
71

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
72
#include <vlc_charset.h>
73
#include <vlc_fs.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
74
#include <vlc_cpu.h>
75
#include <vlc_url.h>
76
#include <vlc_atomic.h>
77
#include <vlc_modules.h>
78

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
79
#include "libvlc.h"
80

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
81
#include "playlist/playlist_internal.h"
82

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
83
#include <vlc_vlm.h>
84

85
86
87
88
#ifdef __APPLE__
# include <libkern/OSAtomic.h>
#endif

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
89
#include <assert.h>
90

91
/*****************************************************************************
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
92
 * The evil global variables. We handle them with care, don't worry.
93
 *****************************************************************************/
94

KO Myung-Hun's avatar
KO Myung-Hun committed
95
#if !defined(WIN32) && !defined(__OS2__)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
96
static bool b_daemon = false;
97
#endif
98

99
100
101
#undef vlc_gc_init
#undef vlc_hold
#undef vlc_release
102

103
104
105
106
107
108
109
110
/**
 * Atomically set the reference count to 1.
 * @param p_gc reference counted object
 * @param pf_destruct destruction calback
 * @return p_gc.
 */
void *vlc_gc_init (gc_object_t *p_gc, void (*pf_destruct) (gc_object_t *))
{
geal's avatar
geal committed
111
    /* There is no point in using the GC if there is no destructor... */
112
    assert (pf_destruct);
113
114
    p_gc->pf_destructor = pf_destruct;

115
    vlc_atomic_set (&p_gc->refs, 1);
116
    return p_gc;
117
118
}

119
120
121
122
123
124
/**
 * Atomically increment the reference count.
 * @param p_gc reference counted object
 * @return p_gc.
 */
void *vlc_hold (gc_object_t * p_gc)
125
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
126
    uintptr_t refs;
127

128
    assert( p_gc );
129
    refs = vlc_atomic_inc (&p_gc->refs);
130
    assert (refs != 1); /* there had to be a reference already */
131
    return p_gc;
132
133
}

134
135
136
137
138
/**
 * Atomically decrement the reference count and, if it reaches zero, destroy.
 * @param p_gc reference counted object.
 */
void vlc_release (gc_object_t *p_gc)
139
{
140
    uintptr_t refs;
141
142

    assert( p_gc );
143
    refs = vlc_atomic_dec (&p_gc->refs);
144
145
    assert (refs != (uintptr_t)(-1)); /* reference underflow?! */
    if (refs == 0)
146
        p_gc->pf_destructor (p_gc);
147
148
}

149
/*****************************************************************************
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
150
 * Local prototypes
151
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Oops    
Rémi Denis-Courmont committed
152
153
154
155
#if defined( ENABLE_NLS ) && (defined (__APPLE__) || defined (WIN32)) && \
    ( defined( HAVE_GETTEXT ) || defined( HAVE_INCLUDED_GETTEXT ) )
static void SetLanguage   ( char const * );
#endif
156
static void GetFilenames  ( libvlc_int_t *, unsigned, const char *const [] );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
157

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
158
159
160
161
162
163
164
165
166
167
168
169
170
/**
 * Allocate a libvlc instance, initialize global data if needed
 * It also initializes the threading system
 */
libvlc_int_t * libvlc_InternalCreate( void )
{
    libvlc_int_t *p_libvlc;
    libvlc_priv_t *priv;
    char *psz_env = NULL;

    /* Now that the thread system is initialized, we don't have much, but
     * at least we have variables */
    /* Allocate a libvlc instance object */
171
    p_libvlc = vlc_custom_create( (vlc_object_t *)NULL, sizeof (*priv),
172
                                  "libvlc" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
173
174
175
176
177
    if( p_libvlc == NULL )
        return NULL;

    priv = libvlc_priv (p_libvlc);
    priv->p_playlist = NULL;
jetru's avatar
jetru committed
178
    priv->p_ml = NULL;
179
    priv->p_dialog_provider = NULL;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
180
181
182
183
184
185
    priv->p_vlm = NULL;

    /* Find verbosity from VLC_VERBOSE environment variable */
    psz_env = getenv( "VLC_VERBOSE" );
    if( psz_env != NULL )
        priv->i_verbose = atoi( psz_env );
186
    else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
187
188
189
190
191
192
193
194
        priv->i_verbose = 3;
#if defined( HAVE_ISATTY ) && !defined( WIN32 )
    priv->b_color = isatty( 2 ); /* 2 is for stderr */
#else
    priv->b_color = false;
#endif

    /* Initialize mutexes */
jetru's avatar
jetru committed
195
    vlc_mutex_init( &priv->ml_lock );
196
    vlc_ExitInit( &priv->exit );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
197
198

    return p_libvlc;
hartman's avatar
hartman committed
199
200
201
}

/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
202
203
204
205
206
207
 * Initialize a libvlc instance
 * This function initializes a previously allocated libvlc instance:
 *  - CPU detection
 *  - gettext initialization
 *  - message queue, module bank and playlist initialization
 *  - configuration and commandline parsing
hartman's avatar
hartman committed
208
 */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
209
int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
210
                         const char *ppsz_argv[] )
hartman's avatar
hartman committed
211
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
212
213
214
215
216
    libvlc_priv_t *priv = libvlc_priv (p_libvlc);
    char *       psz_modules = NULL;
    char *       psz_parser = NULL;
    char *       psz_control = NULL;
    playlist_t  *p_playlist = NULL;
ivoire's avatar
ivoire committed
217
    char        *psz_val;
hartman's avatar
hartman committed
218

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
219
    /* System specific initialization code */
220
    system_Init();
hartman's avatar
hartman committed
221

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
222
223
224
225
    /* Initialize the module bank and load the configuration of the
     * main module. We need to do this at this stage to be able to display
     * a short help if required by the user. (short help == main module
     * options) */
226
    module_InitBank ();
hartman's avatar
hartman committed
227

228
    /* Get command line options that affect module loading. */
229
    if( config_LoadCmdLine( p_libvlc, i_argc, ppsz_argv, NULL ) )
hartman's avatar
hartman committed
230
    {
231
        module_EndBank (false);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
232
        return VLC_EGENERIC;
hartman's avatar
hartman committed
233
    }
234
    priv->i_verbose = var_InheritInteger( p_libvlc, "verbose" );
235
236

    /* Announce who we are (TODO: only first instance?) */
237
    msg_Dbg( p_libvlc, "VLC media player - %s", VERSION_MESSAGE );
238
    msg_Dbg( p_libvlc, "%s", COPYRIGHT_MESSAGE );
239
240
    msg_Dbg( p_libvlc, "revision %s", psz_vlc_changeset );
    msg_Dbg( p_libvlc, "configured with %s", CONFIGURE_LINE );
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265

    /* Load the builtins and plugins into the module_bank.
     * We have to do it before config_Load*() because this also gets the
     * list of configuration options exported by each module and loads their
     * default values. */
    size_t module_count = module_LoadPlugins (p_libvlc);

    /*
     * Override default configuration with config file settings
     */
    if( !var_InheritBool( p_libvlc, "ignore-config" ) )
    {
        if( var_InheritBool( p_libvlc, "reset-config" ) )
            config_SaveConfigFile( p_libvlc ); /* Save default config */
        else
            config_LoadConfigFile( p_libvlc );
    }

    /*
     * Override configuration with command line settings
     */
    int vlc_optind;
    if( config_LoadCmdLine( p_libvlc, i_argc, ppsz_argv, &vlc_optind ) )
    {
#ifdef WIN32
266
267
268
        MessageBox (NULL, TEXT("The command line options could not be parsed.\n"
                    "Make sure they are valid."), TEXT("VLC media player"),
                    MB_OK|MB_ICONERROR);
269
270
271
272
273
274
#endif
        module_EndBank (true);
        return VLC_EGENERIC;
    }
    priv->i_verbose = var_InheritInteger( p_libvlc, "verbose" );

275
276
277
278
279
280
281
282
283
284
285
286
287
288
    /*
     * Support for gettext
     */
#if defined( ENABLE_NLS ) \
     && ( defined( HAVE_GETTEXT ) || defined( HAVE_INCLUDED_GETTEXT ) )
# if defined (WIN32) || defined (__APPLE__)
    /* Check if the user specified a custom language */
    char *lang = var_InheritString (p_libvlc, "language");
    if (lang != NULL && strcmp (lang, "auto"))
        SetLanguage (lang);
    free (lang);
# endif
    vlc_bindtextdomain (PACKAGE_NAME);
#endif
289
    /*xgettext: Translate "C" to the language code: "fr", "en_GB", "nl", "ru"... */
290
    msg_Dbg( p_libvlc, "translation test: code is \"%s\"", _("C") );
291

292
    if (config_PrintHelp (VLC_OBJECT(p_libvlc)))
293
294
295
    {
        module_EndBank (true);
        return VLC_EEXITSUCCESS;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
296
    }
hartman's avatar
hartman committed
297

298
    if( module_count <= 1 )
299
    {
300
        msg_Err( p_libvlc, "No plugins found! Check your VLC installation.");
301
302
        module_EndBank (true);
        return VLC_ENOITEM;
303
304
    }

305
306
307
#ifdef HAVE_DAEMON
    /* Check for daemon mode */
    if( var_InheritBool( p_libvlc, "daemon" ) )
hartman's avatar
hartman committed
308
    {
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
        char *psz_pidfile = NULL;

        if( daemon( 1, 0) != 0 )
        {
            msg_Err( p_libvlc, "Unable to fork vlc to daemon mode" );
            module_EndBank (true);
            return VLC_EEXIT;
        }
        b_daemon = true;

        /* lets check if we need to write the pidfile */
        psz_pidfile = var_CreateGetNonEmptyString( p_libvlc, "pidfile" );
        if( psz_pidfile != NULL )
        {
            FILE *pidfile;
            pid_t i_pid = getpid ();
            msg_Dbg( p_libvlc, "PID is %d, writing it to %s",
                               i_pid, psz_pidfile );
            pidfile = vlc_fopen( psz_pidfile,"w" );
            if( pidfile != NULL )
            {
                utf8_fprintf( pidfile, "%d", (int)i_pid );
                fclose( pidfile );
            }
            else
            {
                msg_Err( p_libvlc, "cannot open pid file for writing: %s (%m)",
                         psz_pidfile );
            }
        }
        free( psz_pidfile );
hartman's avatar
hartman committed
340
    }
341
#endif
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
342
343

/* FIXME: could be replaced by using Unix sockets */
344
#ifdef HAVE_DBUS
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
345
    dbus_threads_init_default();
hartman's avatar
hartman committed
346

347
348
349
    if( var_InheritBool( p_libvlc, "one-instance" )
    || ( var_InheritBool( p_libvlc, "one-instance-when-started-from-file" )
      && var_InheritBool( p_libvlc, "started-from-file" ) ) )
hartman's avatar
hartman committed
350
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
        /* Initialise D-Bus interface, check for other instances */
        DBusConnection  *p_conn = NULL;
        DBusError       dbus_error;

        dbus_error_init( &dbus_error );

        /* connect to the session bus */
        p_conn = dbus_bus_get( DBUS_BUS_SESSION, &dbus_error );
        if( !p_conn )
        {
            msg_Err( p_libvlc, "Failed to connect to D-Bus session daemon: %s",
                    dbus_error.message );
            dbus_error_free( &dbus_error );
        }
        else
        {
            /* check if VLC is available on the bus
             * if not: D-Bus control is not enabled on the other
             * instance and we can't pass MRLs to it */
370
            DBusMessage *p_test_msg   = NULL;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
371
            DBusMessage *p_test_reply = NULL;
372

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
373
            p_test_msg =  dbus_message_new_method_call(
374
                    "org.mpris.MediaPlayer2.vlc", "/org/mpris/MediaPlayer2",
Rafaël Carré's avatar
Rafaël Carré committed
375
                    "org.freedesktop.DBus.Introspectable", "Introspect" );
376

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
            /* block until a reply arrives */
            p_test_reply = dbus_connection_send_with_reply_and_block(
                    p_conn, p_test_msg, -1, &dbus_error );
            dbus_message_unref( p_test_msg );
            if( p_test_reply == NULL )
            {
                dbus_error_free( &dbus_error );
                msg_Dbg( p_libvlc, "No Media Player is running. "
                        "Continuing normally." );
            }
            else
            {
                int i_input;
                DBusMessage* p_dbus_msg = NULL;
                DBusMessageIter dbus_args;
                DBusPendingCall* p_dbus_pending = NULL;
                dbus_bool_t b_play;

                dbus_message_unref( p_test_reply );
                msg_Warn( p_libvlc, "Another Media Player is running. Exiting");

398
                for( i_input = vlc_optind; i_input < i_argc;i_input++ )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
399
                {
400
401
402
403
404
405
406
407
                    /* Skip input options, we can't pass them through D-Bus */
                    if( ppsz_argv[i_input][0] == ':' )
                    {
                        msg_Warn( p_libvlc, "Ignoring option %s",
                                  ppsz_argv[i_input] );
                        continue;
                    }

408
409
                    /* We need to resolve relative paths in this instance */
                    char *psz_mrl = make_URI( ppsz_argv[i_input], NULL );
Rémi Denis-Courmont's avatar
Warning    
Rémi Denis-Courmont committed
410
                    const char *psz_after_track = "/";
411

412
413
                    if( psz_mrl == NULL )
                        continue;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
414
                    msg_Dbg( p_libvlc, "Adds %s to the running Media Player",
415
                             psz_mrl );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
416
417

                    p_dbus_msg = dbus_message_new_method_call(
418
419
                        "org.mpris.MediaPlayer2.vlc", "/org/mpris/MediaPlayer2",
                        "org.mpris.MediaPlayer2.TrackList", "AddTrack" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
420
421
422
423

                    if ( NULL == p_dbus_msg )
                    {
                        msg_Err( p_libvlc, "D-Bus problem" );
424
                        free( psz_mrl );
425
                        system_End( );
426
                        exit( 1 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
427
428
429
430
431
                    }

                    /* append MRLs */
                    dbus_message_iter_init_append( p_dbus_msg, &dbus_args );
                    if ( !dbus_message_iter_append_basic( &dbus_args,
432
                                DBUS_TYPE_STRING, &psz_mrl ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
433
434
                    {
                        dbus_message_unref( p_dbus_msg );
435
                        free( psz_mrl );
436
                        system_End( );
437
                        exit( 1 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
438
                    }
439
                    free( psz_mrl );
440
441
442
443
444

                    if( !dbus_message_iter_append_basic( &dbus_args,
                                DBUS_TYPE_OBJECT_PATH, &psz_after_track ) )
                    {
                        dbus_message_unref( p_dbus_msg );
445
                        system_End( );
446
447
448
                        exit( 1 );
                    }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
449
                    b_play = TRUE;
450
                    if( var_InheritBool( p_libvlc, "playlist-enqueue" ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
451
                        b_play = FALSE;
452

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
453
454
455
456
                    if ( !dbus_message_iter_append_basic( &dbus_args,
                                DBUS_TYPE_BOOLEAN, &b_play ) )
                    {
                        dbus_message_unref( p_dbus_msg );
457
                        system_End( );
458
                        exit( 1 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
459
460
461
462
463
464
465
466
                    }

                    /* send message and get a handle for a reply */
                    if ( !dbus_connection_send_with_reply ( p_conn,
                                p_dbus_msg, &p_dbus_pending, -1 ) )
                    {
                        msg_Err( p_libvlc, "D-Bus problem" );
                        dbus_message_unref( p_dbus_msg );
467
                        system_End( );
468
                        exit( 1 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
469
470
471
472
473
474
                    }

                    if ( NULL == p_dbus_pending )
                    {
                        msg_Err( p_libvlc, "D-Bus problem" );
                        dbus_message_unref( p_dbus_msg );
475
                        system_End( );
476
                        exit( 1 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
477
478
479
480
481
482
483
484
485
                    }
                    dbus_connection_flush( p_conn );
                    dbus_message_unref( p_dbus_msg );
                    /* block until we receive a reply */
                    dbus_pending_call_block( p_dbus_pending );
                    dbus_pending_call_unref( p_dbus_pending );
                } /* processes all command line MRLs */

                /* bye bye */
486
                system_End( );
487
                exit( 0 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
488
489
490
491
            }
        }
        /* we unreference the connection when we've finished with it */
        if( p_conn ) dbus_connection_unref( p_conn );
hartman's avatar
hartman committed
492
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
493
#endif
hartman's avatar
hartman committed
494

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
495
496
497
    /*
     * Message queue options
     */
498
    /* Last chance to set the verbosity. Once we start interfaces and other
499
     * threads, verbosity becomes read-only. */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
500
    var_Create( p_libvlc, "verbose", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
501
    if( var_InheritBool( p_libvlc, "quiet" ) )
hartman's avatar
hartman committed
502
    {
503
504
        var_SetInteger( p_libvlc, "verbose", -1 );
        priv->i_verbose = -1;
hartman's avatar
hartman committed
505
    }
506
    vlc_threads_setup( p_libvlc );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
507
508

    if( priv->b_color )
509
        priv->b_color = var_InheritBool( p_libvlc, "color" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
510

511
    vlc_CPU_dump( VLC_OBJECT(p_libvlc) );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
512
513
514
    /*
     * Choose the best memcpy module
     */
515
    priv->p_memcpy_module = module_need( p_libvlc, "memcpy", "$memcpy", false );
516
517
    /* Avoid being called "memcpy":*/
    vlc_object_set_name( p_libvlc, "main" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
518

519
    priv->b_stats = var_InheritBool( p_libvlc, "stats" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
520
521
522
523

    /*
     * Initialize hotkey handling
     */
524
    priv->actions = vlc_InitActions( p_libvlc );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
525

526
    /* Create a variable for showing the fullscreen interface */
527
528
    var_Create( p_libvlc, "intf-toggle-fscontrol", VLC_VAR_BOOL );
    var_SetBool( p_libvlc, "intf-toggle-fscontrol", true );
529

530
531
532
    /* Create a variable for the Boss Key */
    var_Create( p_libvlc, "intf-boss", VLC_VAR_VOID );

533
534
535
    /* Create a variable for showing the main interface */
    var_Create( p_libvlc, "intf-show", VLC_VAR_BOOL );

536
537
538
    /* Create a variable for showing the right click menu */
    var_Create( p_libvlc, "intf-popupmenu", VLC_VAR_BOOL );

539
540
541
542
    /* variables for signalling creation of new files */
    var_Create( p_libvlc, "snapshot-file", VLC_VAR_STRING );
    var_Create( p_libvlc, "record-file", VLC_VAR_STRING );

543
    /* some default internal settings */
544
    var_Create( p_libvlc, "window", VLC_VAR_STRING );
545
546
    var_Create( p_libvlc, "user-agent", VLC_VAR_STRING );
    var_SetString( p_libvlc, "user-agent", "(LibVLC "VERSION")" );
547

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
548
    /* Initialize playlist and get commandline files */
549
550
    p_playlist = playlist_Create( VLC_OBJECT(p_libvlc) );
    if( !p_playlist )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
551
552
553
554
    {
        msg_Err( p_libvlc, "playlist initialization failed" );
        if( priv->p_memcpy_module != NULL )
        {
555
            module_unneed( p_libvlc, priv->p_memcpy_module );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
556
        }
557
        module_EndBank (true);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
558
559
        return VLC_EGENERIC;
    }
hartman's avatar
hartman committed
560

561
    /* System specific configuration */
562
    system_Configure( p_libvlc, i_argc - vlc_optind, ppsz_argv + vlc_optind );
563

jetru's avatar
jetru committed
564
565
#if defined(MEDIA_LIBRARY)
    /* Get the ML */
ivoire's avatar
ivoire committed
566
    if( var_GetBool( p_libvlc, "load-media-library-on-startup" ) )
jetru's avatar
jetru committed
567
    {
568
        priv->p_ml = ml_Create( VLC_OBJECT( p_libvlc ), NULL );
jetru's avatar
jetru committed
569
570
571
572
573
574
575
576
577
578
579
580
        if( !priv->p_ml )
        {
            msg_Err( p_libvlc, "ML initialization failed" );
            return VLC_EGENERIC;
        }
    }
    else
    {
        priv->p_ml = NULL;
    }
#endif

581
    /* Add service discovery modules */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
582
    psz_modules = var_InheritString( p_libvlc, "services-discovery" );
583
    if( psz_modules )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
584
    {
585
586
587
        char *p = psz_modules, *m;
        while( ( m = strsep( &p, " :," ) ) != NULL )
            playlist_ServicesDiscoveryAdd( p_playlist, m );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
588
        free( psz_modules );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
589
    }
hartman's avatar
hartman committed
590

591
#ifdef ENABLE_VLM
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
592
    /* Initialize VLM if vlm-conf is specified */
593
594
    psz_parser = var_CreateGetNonEmptyString( p_libvlc, "vlm-conf" );
    if( psz_parser )
hartman's avatar
hartman committed
595
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
596
597
598
        priv->p_vlm = vlm_New( p_libvlc );
        if( !priv->p_vlm )
            msg_Err( p_libvlc, "VLM initialization failed" );
hartman's avatar
hartman committed
599
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
600
601
    free( psz_parser );
#endif
hartman's avatar
hartman committed
602

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
603
604
605
    /*
     * Load background interfaces
     */
606
607
    psz_modules = var_CreateGetNonEmptyString( p_libvlc, "extraintf" );
    psz_control = var_CreateGetNonEmptyString( p_libvlc, "control" );
hartman's avatar
hartman committed
608

609
    if( psz_modules && psz_control )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
610
    {
611
612
613
614
615
616
        char* psz_tmp;
        if( asprintf( &psz_tmp, "%s:%s", psz_modules, psz_control ) != -1 )
        {
            free( psz_modules );
            psz_modules = psz_tmp;
        }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
617
    }
618
    else if( psz_control )
hartman's avatar
hartman committed
619
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
620
621
        free( psz_modules );
        psz_modules = strdup( psz_control );
hartman's avatar
hartman committed
622
623
    }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
624
625
626
627
628
629
630
631
632
633
634
    psz_parser = psz_modules;
    while ( psz_parser && *psz_parser )
    {
        char *psz_module, *psz_temp;
        psz_module = psz_parser;
        psz_parser = strchr( psz_module, ':' );
        if ( psz_parser )
        {
            *psz_parser = '\0';
            psz_parser++;
        }
635
        if( asprintf( &psz_temp, "%s,none", psz_module ) != -1)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
636
        {
637
            intf_Create( p_libvlc, psz_temp );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
638
639
640
641
642
643
644
645
646
            free( psz_temp );
        }
    }
    free( psz_modules );
    free( psz_control );

    /*
     * Always load the hotkeys interface if it exists
     */
647
    intf_Create( p_libvlc, "hotkeys,none" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
648

649
#ifdef HAVE_DBUS
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
650
651
    /* loads dbus control interface if in one-instance mode
     * we do it only when playlist exists, because dbus module needs it */
652
653
654
    if( var_InheritBool( p_libvlc, "one-instance" )
     || ( var_InheritBool( p_libvlc, "one-instance-when-started-from-file" )
       && var_InheritBool( p_libvlc, "started-from-file" ) ) )
655
        intf_Create( p_libvlc, "dbus,none" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
656

657
# if !defined (HAVE_MAEMO)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
658
659
    /* Prevents the power management daemon from suspending the system
     * when VLC is active */
660
    if( var_InheritBool( p_libvlc, "inhibit" ) > 0 )
661
        intf_Create( p_libvlc, "inhibit,none" );
662
# endif
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
663
#endif
hartman's avatar
hartman committed
664

665
666
    if( var_InheritBool( p_libvlc, "file-logging" ) &&
        !var_InheritBool( p_libvlc, "syslog" ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
667
    {
668
        intf_Create( p_libvlc, "logger,none" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
669
670
    }
#ifdef HAVE_SYSLOG_H
671
    if( var_InheritBool( p_libvlc, "syslog" ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
672
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
673
        char *logmode = var_CreateGetNonEmptyString( p_libvlc, "logmode" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
674
        var_SetString( p_libvlc, "logmode", "syslog" );
675
        intf_Create( p_libvlc, "logger,none" );
hartman's avatar
hartman committed
676

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
677
678
679
680
681
        if( logmode )
        {
            var_SetString( p_libvlc, "logmode", logmode );
            free( logmode );
        }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
682
        var_Destroy( p_libvlc, "logmode" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
683
684
685
    }
#endif

686
    if( var_InheritBool( p_libvlc, "network-synchronisation") )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
687
    {
688
        intf_Create( p_libvlc, "netsync,none" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
689
    }
hartman's avatar
hartman committed
690

691
#ifdef __APPLE__
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
692
693
694
695
696
697
698
699
    var_Create( p_libvlc, "drawable-view-top", VLC_VAR_INTEGER );
    var_Create( p_libvlc, "drawable-view-left", VLC_VAR_INTEGER );
    var_Create( p_libvlc, "drawable-view-bottom", VLC_VAR_INTEGER );
    var_Create( p_libvlc, "drawable-view-right", VLC_VAR_INTEGER );
    var_Create( p_libvlc, "drawable-clip-top", VLC_VAR_INTEGER );
    var_Create( p_libvlc, "drawable-clip-left", VLC_VAR_INTEGER );
    var_Create( p_libvlc, "drawable-clip-bottom", VLC_VAR_INTEGER );
    var_Create( p_libvlc, "drawable-clip-right", VLC_VAR_INTEGER );
700
    var_Create( p_libvlc, "drawable-nsobject", VLC_VAR_ADDRESS );
701
#endif
702
#if defined (WIN32) || defined (__OS2__)
703
    var_Create( p_libvlc, "drawable-hwnd", VLC_VAR_INTEGER );
704
#endif
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
705
706

    /*
707
708
709
     * Get input filenames given as commandline arguments.
     * We assume that the remaining parameters are filenames
     * and their input options.
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
710
     */
711
    GetFilenames( p_libvlc, i_argc - vlc_optind, ppsz_argv + vlc_optind );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
712
713
714
715

    /*
     * Get --open argument
     */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
716
    psz_val = var_InheritString( p_libvlc, "open" );
717
    if ( psz_val != NULL )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
718
    {
ivoire's avatar
ivoire committed
719
        playlist_AddExt( p_playlist, psz_val, NULL, PLAYLIST_INSERT, 0,
720
                         -1, 0, NULL, 0, true, pl_Unlocked );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
721
        free( psz_val );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
722
    }
hartman's avatar
hartman committed
723

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
724
    return VLC_SUCCESS;
hartman's avatar
hartman committed
725
726
727
}

/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
728
729
 * Cleanup a libvlc instance. The instance is not completely deallocated
 * \param p_libvlc the instance to clean
hartman's avatar
hartman committed
730
 */
731
void libvlc_InternalCleanup( libvlc_int_t *p_libvlc )
hartman's avatar
hartman committed
732
{
733
    libvlc_priv_t *priv = libvlc_priv (p_libvlc);
734
    playlist_t    *p_playlist = libvlc_priv (p_libvlc)->p_playlist;
735
736
737

    /* Deactivate the playlist */
    msg_Dbg( p_libvlc, "deactivating the playlist" );
738
    pl_Deactivate( p_libvlc );
739
740
741
742

    /* Remove all services discovery */
    msg_Dbg( p_libvlc, "removing all services discovery tasks" );
    playlist_ServicesDiscoveryKillAll( p_playlist );
hartman's avatar
hartman committed
743

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
744
745
    /* Ask the interfaces to stop and destroy them */
    msg_Dbg( p_libvlc, "removing all interfaces" );
746
    libvlc_Quit( p_libvlc );
747
    intf_DestroyAll( p_libvlc );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
748

749
#ifdef ENABLE_VLM
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
750
751
752
753
754
755
756
    /* Destroy VLM if created in libvlc_InternalInit */
    if( priv->p_vlm )
    {
        vlm_Delete( priv->p_vlm );
    }
#endif

757
758
759
760
761
762
763
764
765
766
#if defined(MEDIA_LIBRARY)
    media_library_t* p_ml = priv->p_ml;
    if( p_ml )
    {
        ml_Destroy( VLC_OBJECT( p_ml ) );
        vlc_object_release( p_ml );
        libvlc_priv(p_playlist->p_libvlc)->p_ml = NULL;
    }
#endif

767
768
    /* Free playlist now, all threads are gone */
    playlist_Destroy( p_playlist );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
769
770
771

    msg_Dbg( p_libvlc, "removing stats" );

KO Myung-Hun's avatar
KO Myung-Hun committed
772
#if !defined( WIN32 ) && !defined( __OS2__ )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
773
774
775
776
    char* psz_pidfile = NULL;

    if( b_daemon )
    {
777
        psz_pidfile = var_CreateGetNonEmptyString( p_libvlc, "pidfile" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
        if( psz_pidfile != NULL )
        {
            msg_Dbg( p_libvlc, "removing pid file %s", psz_pidfile );
            if( unlink( psz_pidfile ) == -1 )
            {
                msg_Dbg( p_libvlc, "removing pid file %s: %m",
                        psz_pidfile );
            }
        }
        free( psz_pidfile );
    }
#endif

    if( priv->p_memcpy_module )
    {
793
        module_unneed( p_libvlc, priv->p_memcpy_module );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
794
795
796
        priv->p_memcpy_module = NULL;
    }

797
798
799
800
    /* Save the configuration */
    if( !var_InheritBool( p_libvlc, "ignore-config" ) )
        config_AutoSaveConfigFile( VLC_OBJECT(p_libvlc) );

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
801
    /* Free module bank. It is refcounted, so we call this each time  */
802
    module_EndBank (true);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
803

804
    vlc_DeinitActions( p_libvlc, priv->actions );
805
806
807
808
809
810
811
812
813
814
815
816
}

/**
 * Destroy everything.
 * This function requests the running threads to finish, waits for their
 * termination, and destroys their structure.
 * It stops the thread systems: no instance can run after this has run
 * \param p_libvlc the instance to destroy
 */
void libvlc_InternalDestroy( libvlc_int_t *p_libvlc )
{
    libvlc_priv_t *priv = libvlc_priv( p_libvlc );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
817

818
    system_End( );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
819
820

    /* Destroy mutexes */
821
    vlc_ExitDestroy( &priv->exit );
jetru's avatar
jetru committed
822
    vlc_mutex_destroy( &priv->ml_lock );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
823

824
825
826
827
828
829
#ifndef NDEBUG /* Hack to dump leaked objects tree */
    if( vlc_internals( p_libvlc )->i_refcount > 1 )
        while( vlc_internals( p_libvlc )->i_refcount > 0 )
            vlc_object_release( p_libvlc );
#endif

830
    assert( vlc_internals( p_libvlc )->i_refcount == 1 );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
831
    vlc_object_release( p_libvlc );
hartman's avatar
hartman committed
832
833
834
}

/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
835
 * Add an interface plugin and run it
hartman's avatar
hartman committed
836
 */
837
int libvlc_InternalAddIntf( libvlc_int_t *p_libvlc, char const *psz_module )
hartman's avatar
hartman committed
838
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
839
840
841
842
843
    if( !p_libvlc )
        return VLC_EGENERIC;

    if( !psz_module ) /* requesting the default interface */
    {
844
845
        char *psz_interface = var_CreateGetNonEmptyString( p_libvlc, "intf" );
        if( !psz_interface ) /* "intf" has not been set */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
846
        {
KO Myung-Hun's avatar
KO Myung-Hun committed
847
#if !defined( WIN32 ) && !defined( __OS2__ )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
848
849
850
851
852
853
            if( b_daemon )
                 /* Daemon mode hack.
                  * We prefer the dummy interface if none is specified. */
                psz_module = "dummy";
            else
#endif
854
855
856
                msg_Info( p_libvlc, "%s",
                          _("Running vlc with the default interface. "
                            "Use 'cvlc' to use vlc without interface.") );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
857
858
        }
        free( psz_interface );
859
        var_Destroy( p_libvlc, "intf" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
860
861
862
    }

    /* Try to create the interface */
863
864
    int ret = intf_Create( p_libvlc, psz_module ? psz_module : "$intf" );
    if( ret )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
865
        msg_Err( p_libvlc, "interface \"%s\" initialization failed",
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
866
                 psz_module ? psz_module : "default" );
867
    return ret;
868
}
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890

#if defined( ENABLE_NLS ) && (defined (__APPLE__) || defined (WIN32)) && \
    ( defined( HAVE_GETTEXT ) || defined( HAVE_INCLUDED_GETTEXT ) )
/*****************************************************************************
 * SetLanguage: set the interface language.
 *****************************************************************************
 * We set the LC_MESSAGES locale category for interface messages and buttons,
 * as well as the LC_CTYPE category for string sorting and possible wide
 * character support.
 *****************************************************************************/
static void SetLanguage ( const char *psz_lang )
{
#ifdef __APPLE__
    /* I need that under Darwin, please check it doesn't disturb
     * other platforms. --Meuuh */
    setenv( "LANG", psz_lang, 1 );

#else
    /* We set LC_ALL manually because it is the only way to set
     * the language at runtime under eg. Windows. Beware that this
     * makes the environment unconsistent when libvlc is unloaded and
     * should probably be moved to a safer place like vlc.c. */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
891
892
    setenv( "LC_ALL", psz_lang, 1 );

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
893
894
895
#endif

    setlocale( LC_ALL, psz_lang );
896
}
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
897
#endif
898

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
899
900
901
902
903
904
/*****************************************************************************
 * GetFilenames: parse command line options which are not flags
 *****************************************************************************
 * Parse command line for input files as well as their associated options.
 * An option always follows its associated input and begins with a ":".
 *****************************************************************************/
905
906
static void GetFilenames( libvlc_int_t *p_vlc, unsigned n,
                          const char *const args[] )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
907
{
908
    while( n > 0 )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
909
910
    {
        /* Count the input options */
911
912
913
        unsigned i_options = 0;

        while( args[--n][0] == ':' )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
914
915
        {
            i_options++;
916
917
918
919
920
            if( n == 0 )
            {
                msg_Warn( p_vlc, "options %s without item", args[n] );
                return; /* syntax!? */
            }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
921
922
        }

923
        char *mrl = make_URI( args[n], NULL );
924
925
        if( !mrl )
            continue;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
926

927
        playlist_AddExt( pl_Get( p_vlc ), mrl, NULL, PLAYLIST_INSERT,
928
                0, -1, i_options, ( i_options ? &args[n + 1] : NULL ),
929
930
                VLC_INPUT_OPTION_TRUSTED, true, pl_Unlocked );
        free( mrl );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
931
    }
932
}