]> git.sesse.net Git - vlc/blob - src/interface/interface.c
decoder: do not wait for buffering when there is no data
[vlc] / src / interface / interface.c
1 /*****************************************************************************
2  * interface.c: interface access for other threads
3  * This library provides basic functions for threads to interact with user
4  * interface, such as command line.
5  *****************************************************************************
6  * Copyright (C) 1998-2007 VLC authors and VideoLAN
7  * $Id$
8  *
9  * Authors: Vincent Seguin <seguin@via.ecp.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation; either version 2.1 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /**
27  *   \file
28  *   This file contains functions related to interface management
29  */
30
31
32 /*****************************************************************************
33  * Preamble
34  *****************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
39
40 #include <unistd.h>
41 #include <assert.h>
42
43 #include <vlc_common.h>
44 #include <vlc_modules.h>
45 #include <vlc_interface.h>
46 #include <vlc_playlist.h>
47 #include "libvlc.h"
48 #include "playlist/playlist_internal.h"
49 #include "../lib/libvlc_internal.h"
50
51 static int AddIntfCallback( vlc_object_t *, char const *,
52                             vlc_value_t , vlc_value_t , void * );
53
54 /* This lock ensures that the playlist is created only once (per instance). It
55  * also protects the list of running interfaces against concurrent access,
56  * either to add or remove an interface.
57  *
58  * However, it does NOT protect from destruction of the playlist by
59  * intf_DestroyAll(). Instead, care must be taken that intf_Create() and any
60  * other function that depends on the playlist is only called BEFORE
61  * intf_DestroyAll() has the possibility to destroy all interfaces.
62  */
63 static vlc_mutex_t lock = VLC_STATIC_MUTEX;
64
65 /**
66  * Create and start an interface.
67  *
68  * @param playlist playlist and parent object for the interface
69  * @param chain configuration chain string
70  * @return VLC_SUCCESS or an error code
71  */
72 int intf_Create( playlist_t *playlist, const char *chain )
73 {
74     /* Allocate structure */
75     intf_thread_t *p_intf = vlc_custom_create( playlist, sizeof( *p_intf ),
76                                                "interface" );
77     if( unlikely(p_intf == NULL) )
78         return VLC_ENOMEM;
79
80     /* Variable used for interface spawning */
81     vlc_value_t val, text;
82     var_Create( p_intf, "intf-add", VLC_VAR_STRING |
83                 VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
84     text.psz_string = _("Add Interface");
85     var_Change( p_intf, "intf-add", VLC_VAR_SETTEXT, &text, NULL );
86 #if !defined(_WIN32) && defined(HAVE_ISATTY)
87     if( isatty( 0 ) )
88 #endif
89     {
90         val.psz_string = (char *)"rc,none";
91         text.psz_string = (char *)_("Console");
92         var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
93     }
94     val.psz_string = (char *)"telnet,none";
95     text.psz_string = (char *)_("Telnet");
96     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
97     val.psz_string = (char *)"http,none";
98     text.psz_string = (char *)_("Web");
99     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
100     val.psz_string = (char *)"logger,none";
101     text.psz_string = (char *)_("Debug logging");
102     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
103     val.psz_string = (char *)"gestures,none";
104     text.psz_string = (char *)_("Mouse Gestures");
105     var_Change( p_intf, "intf-add", VLC_VAR_ADDCHOICE, &val, &text );
106
107     var_AddCallback( p_intf, "intf-add", AddIntfCallback, playlist );
108
109     /* Choose the best module */
110     char *module;
111
112     p_intf->p_cfg = NULL;
113     free( config_ChainCreate( &module, &p_intf->p_cfg, chain ) );
114     p_intf->p_module = module_need( p_intf, "interface", module, true );
115     free(module);
116     if( p_intf->p_module == NULL )
117     {
118         msg_Err( p_intf, "no suitable interface module" );
119         goto error;
120     }
121
122     vlc_mutex_lock( &lock );
123     p_intf->p_next = pl_priv( playlist )->interface;
124     pl_priv( playlist )->interface = p_intf;
125     vlc_mutex_unlock( &lock );
126
127     return VLC_SUCCESS;
128
129 error:
130     if( p_intf->p_module )
131         module_unneed( p_intf, p_intf->p_module );
132     config_ChainDestroy( p_intf->p_cfg );
133     vlc_object_release( p_intf );
134     return VLC_EGENERIC;
135 }
136
137 /**
138  * Creates the playlist if necessary, and return a pointer to it.
139  * @note The playlist is not reference-counted. So the pointer is only valid
140  * until intf_DestroyAll() destroys interfaces.
141  */
142 static playlist_t *intf_GetPlaylist(libvlc_int_t *libvlc)
143 {
144     playlist_t *playlist;
145
146     vlc_mutex_lock(&lock);
147     playlist = libvlc_priv(libvlc)->playlist;
148     if (playlist == NULL)
149     {
150         playlist = playlist_Create(VLC_OBJECT(libvlc));
151         libvlc_priv(libvlc)->playlist = playlist;
152     }
153     vlc_mutex_unlock(&lock);
154
155     return playlist;
156 }
157
158 /**
159  * Inserts an item in the playlist used by interfaces.
160  * @note This function may <b>not</b> be called at the same time as
161  * intf_DestroyAll().
162  */
163 void intf_InsertItem(libvlc_int_t *libvlc, const char *mrl, unsigned optc,
164                      const char *const *optv, unsigned flags)
165 {
166     playlist_AddExt(intf_GetPlaylist(libvlc), mrl, NULL, PLAYLIST_INSERT,
167                     0, -1, optc, optv, flags, true, pl_Unlocked);
168 }
169
170 void libvlc_InternalPlay(libvlc_int_t *libvlc)
171 {
172     playlist_t *pl;
173
174     vlc_mutex_lock(&lock);
175     pl = libvlc_priv(libvlc)->playlist;
176     vlc_mutex_unlock(&lock);
177
178     if (pl != NULL && var_GetBool(pl, "playlist-autostart"))
179         playlist_Control(pl, PLAYLIST_PLAY, false);
180 }
181
182 /**
183  * Starts an interface plugin.
184  */
185 int libvlc_InternalAddIntf(libvlc_int_t *libvlc, const char *name)
186 {
187     playlist_t *playlist = intf_GetPlaylist(libvlc);
188     int ret;
189
190     if (unlikely(playlist == NULL))
191         ret = VLC_ENOMEM;
192     else
193     if (name != NULL)
194         ret = intf_Create(playlist, name);
195     else
196     {   /* Default interface */
197         char *intf = var_InheritString(libvlc, "intf");
198         if (intf == NULL) /* "intf" has not been set */
199         {
200 #if !defined(_WIN32) && !defined(__OS2__)
201             char *pidfile = var_InheritString(libvlc, "pidfile");
202             if (pidfile != NULL)
203                 free(pidfile);
204             else
205 #endif
206                 msg_Info(libvlc, _("Running vlc with the default interface. "
207                          "Use 'cvlc' to use vlc without interface."));
208         }
209         ret = intf_Create(playlist, intf);
210         free(intf);
211         name = "default";
212     }
213     if (ret != VLC_SUCCESS)
214         msg_Err(libvlc, "interface \"%s\" initialization failed", name);
215     return ret;
216 }
217
218 /**
219  * Stops and destroys all interfaces, then the playlist.
220  * @warning FIXME
221  * @param libvlc the LibVLC instance
222  */
223 void intf_DestroyAll(libvlc_int_t *libvlc)
224 {
225     playlist_t *playlist;
226
227     vlc_mutex_lock(&lock);
228     playlist = libvlc_priv(libvlc)->playlist;
229     if (playlist != NULL)
230     {
231         intf_thread_t *intf, **pp = &(pl_priv(playlist)->interface);
232
233         while ((intf = *pp) != NULL)
234         {
235             *pp = intf->p_next;
236             vlc_mutex_unlock(&lock);
237
238             module_unneed(intf, intf->p_module);
239             config_ChainDestroy(intf->p_cfg);
240             var_DelCallback(intf, "intf-add", AddIntfCallback, playlist);
241             vlc_object_release(intf);
242
243             vlc_mutex_lock(&lock);
244         }
245
246         libvlc_priv(libvlc)->playlist = NULL;
247     }
248     vlc_mutex_unlock(&lock);
249
250     if (playlist != NULL)
251         playlist_Destroy(playlist);
252 }
253
254 /* Following functions are local */
255
256 static int AddIntfCallback( vlc_object_t *obj, char const *var,
257                             vlc_value_t old, vlc_value_t cur, void *data )
258 {
259     playlist_t *playlist = data;
260
261     int ret = intf_Create( playlist, cur.psz_string );
262     if( ret )
263         msg_Err( obj, "interface \"%s\" initialization failed",
264                  cur.psz_string );
265
266     (void) var; (void) old;
267     return ret;
268 }