]> git.sesse.net Git - vlc/blob - modules/misc/lua/libs/misc.c
lua: also implement timer:getoverrun()
[vlc] / modules / misc / lua / libs / misc.c
1 /*****************************************************************************
2  * misc.c
3  *****************************************************************************
4  * Copyright (C) 2007-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea at videolan tod org>
8  *          Pierre d'Herbemont <pdherbemont # videolan.org>
9  *          RĂ©mi Duraffort <ivoire # videolan tod org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 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 General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #ifndef  _GNU_SOURCE
30 #   define  _GNU_SOURCE
31 #endif
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <vlc_common.h>
38 #include <vlc_plugin.h>
39 #include <vlc_meta.h>
40 #include <vlc_aout.h>
41 #include <vlc_interface.h>
42 #include <vlc_keys.h>
43
44 #include <lua.h>        /* Low level lua C API */
45 #include <lauxlib.h>    /* Higher level C API */
46 #include <lualib.h>     /* Lua libs */
47
48 #include "../vlc.h"
49 #include "../libs.h"
50
51 /*****************************************************************************
52  * Internal lua<->vlc utils
53  *****************************************************************************/
54 static void vlclua_set_object( lua_State *L, void *id, void *value )
55 {
56     lua_pushlightuserdata( L, id );
57     lua_pushlightuserdata( L, value );
58     lua_rawset( L, LUA_REGISTRYINDEX );
59 }
60
61 static void *vlclua_get_object( lua_State *L, void *id )
62 {
63     lua_pushlightuserdata( L, id );
64     lua_rawget( L, LUA_REGISTRYINDEX );
65     const void *p = lua_topointer( L, -1 );
66     lua_pop( L, 1 );
67     return (void *)p;
68 }
69
70 #undef vlclua_set_this
71 void vlclua_set_this( lua_State *L, vlc_object_t *p_this )
72 {
73     vlclua_set_object( L, vlclua_set_this, p_this );
74 }
75
76 vlc_object_t * vlclua_get_this( lua_State *L )
77 {
78     return vlclua_get_object( L, vlclua_set_this );
79 }
80
81 void vlclua_set_intf( lua_State *L, intf_sys_t *p_intf )
82 {
83     vlclua_set_object( L, vlclua_set_intf, p_intf );
84 }
85
86 static intf_sys_t * vlclua_get_intf( lua_State *L )
87 {
88     return vlclua_get_object( L, vlclua_set_intf );
89 }
90
91 /*****************************************************************************
92  * VLC error code translation
93  *****************************************************************************/
94 int vlclua_push_ret( lua_State *L, int i_error )
95 {
96     lua_pushnumber( L, i_error );
97     lua_pushstring( L, vlc_error( i_error ) );
98     return 2;
99 }
100
101 /*****************************************************************************
102  * Get the VLC version string
103  *****************************************************************************/
104 static int vlclua_version( lua_State *L )
105 {
106     lua_pushstring( L, VLC_Version() );
107     return 1;
108 }
109
110 /*****************************************************************************
111  * Get the VLC copyright
112  *****************************************************************************/
113 static int vlclua_copyright( lua_State *L )
114 {
115     lua_pushliteral( L, COPYRIGHT_MESSAGE );
116     return 1;
117 }
118
119 /*****************************************************************************
120  * Get the VLC license msg/disclaimer
121  *****************************************************************************/
122 static int vlclua_license( lua_State *L )
123 {
124     lua_pushstring( L, LICENSE_MSG );
125     return 1;
126 }
127
128 /*****************************************************************************
129  * Quit VLC
130  *****************************************************************************/
131 static int vlclua_quit( lua_State *L )
132 {
133     vlc_object_t *p_this = vlclua_get_this( L );
134     /* The rc.c code also stops the playlist ... not sure if this is needed
135      * though. */
136     libvlc_Quit( p_this->p_libvlc );
137     return 0;
138 }
139
140 /*****************************************************************************
141  * Global properties getters
142  *****************************************************************************/
143 static int vlclua_datadir( lua_State *L )
144 {
145     char *psz_data = config_GetDataDir( vlclua_get_this( L ) );
146     lua_pushstring( L, psz_data );
147     free( psz_data );
148     return 1;
149 }
150
151 static int vlclua_userdatadir( lua_State *L )
152 {
153     char *dir = config_GetUserDir( VLC_DATA_DIR );
154     lua_pushstring( L, dir );
155     free( dir );
156     return 1;
157 }
158
159 static int vlclua_homedir( lua_State *L )
160 {
161     char *home = config_GetUserDir( VLC_HOME_DIR );
162     lua_pushstring( L, home );
163     free( home );
164     return 1;
165 }
166
167 static int vlclua_configdir( lua_State *L )
168 {
169     char *dir = config_GetUserDir( VLC_CONFIG_DIR );
170     lua_pushstring( L, dir );
171     free( dir );
172     return 1;
173 }
174
175 static int vlclua_cachedir( lua_State *L )
176 {
177     char *dir = config_GetUserDir( VLC_CACHE_DIR );
178     lua_pushstring( L, dir );
179     free( dir );
180     return 1;
181 }
182
183 static int vlclua_datadir_list( lua_State *L )
184 {
185     const char *psz_dirname = luaL_checkstring( L, 1 );
186     char **ppsz_dir_list = NULL;
187     int i = 1;
188
189     if( vlclua_dir_list( vlclua_get_this( L ), psz_dirname, &ppsz_dir_list )
190         != VLC_SUCCESS )
191         return 0;
192     lua_newtable( L );
193     for( char **ppsz_dir = ppsz_dir_list; *ppsz_dir; ppsz_dir++ )
194     {
195         lua_pushstring( L, *ppsz_dir );
196         lua_rawseti( L, -2, i );
197         i ++;
198     }
199     vlclua_dir_list_free( ppsz_dir_list );
200     return 1;
201 }
202 /*****************************************************************************
203  *
204  *****************************************************************************/
205 static int vlclua_lock_and_wait( lua_State *L )
206 {
207     intf_sys_t *p_sys = vlclua_get_intf( L );
208
209     vlc_mutex_lock( &p_sys->lock );
210     mutex_cleanup_push( &p_sys->lock );
211     while( !p_sys->exiting )
212         vlc_cond_wait( &p_sys->wait, &p_sys->lock );
213     vlc_cleanup_run();
214     lua_pushboolean( L, 1 );
215     return 1;
216 }
217
218 static int vlclua_mdate( lua_State *L )
219 {
220     lua_pushnumber( L, mdate() );
221     return 1;
222 }
223
224 static int vlclua_mwait( lua_State *L )
225 {
226     double f = luaL_checknumber( L, 1 );
227     mwait( (int64_t)f );
228     return 0;
229 }
230
231 static int vlclua_intf_should_die( lua_State *L )
232 {
233     intf_sys_t *p_sys = vlclua_get_intf( L );
234     lua_pushboolean( L, p_sys->exiting );
235     return 1;
236 }
237
238 static int vlclua_action_id( lua_State *L )
239 {
240     vlc_key_t i_key = vlc_GetActionId( luaL_checkstring( L, 1 ) );
241     if (i_key == 0)
242         return 0;
243     lua_pushnumber( L, i_key );
244     return 1;
245 }
246
247 /*****************************************************************************
248  * Timer functions
249  *****************************************************************************/
250 static int vlclua_timer_schedule( lua_State *L );
251 static int vlclua_timer_getoverrun( lua_State *L);
252
253 static const luaL_Reg vlclua_timer_reg[] = {
254     { "schedule",   vlclua_timer_schedule   },
255     { "getoverrun", vlclua_timer_getoverrun },
256     { NULL,         NULL                    }
257 };
258
259 typedef struct
260 {
261     lua_State *L;
262     vlc_timer_t timer;
263     char *psz_callback;
264 } vlclua_timer_t;
265
266 static int vlclua_timer_schedule( lua_State *L )
267 {
268     vlclua_timer_t **pp_timer = (vlclua_timer_t**)luaL_checkudata( L, 1, "timer" );
269     if( !pp_timer || !*pp_timer )
270         luaL_error( L, "Can't get pointer to timer" );
271
272     bool b_relative = luaL_checkboolean( L, 2 );
273     mtime_t i_value = luaL_checkinteger( L, 3 );
274     mtime_t i_interval = luaL_checkinteger( L, 4 );
275
276     vlc_timer_schedule( (*pp_timer)->timer, b_relative, i_value, i_interval );
277     return 0;
278 }
279
280 static int vlclua_timer_getoverrun( lua_State *L )
281 {
282     vlclua_timer_t **pp_timer = (vlclua_timer_t**)luaL_checkudata(L, 1, "timer" );
283     if( !pp_timer || !*pp_timer )
284         luaL_error( L, "Can't get pointer to timer" );
285
286     lua_pushinteger( L, vlc_timer_getoverrun( (*pp_timer)->timer ) );
287     return 1;
288 }
289
290 static void vlclua_timer_callback( void *data )
291 {
292     vlclua_timer_t *p_timer = (vlclua_timer_t*)data;
293     lua_State *L = p_timer->L;
294
295     lua_getglobal( L, p_timer->psz_callback );
296     if( lua_pcall( L, 0, 0, 0 ) )
297     {
298         const char *psz_err = lua_tostring( L, -1 );
299         fprintf( stderr, "Error while running the timer callback: %s\n", psz_err );
300         lua_settop( L, 0 );
301     }
302 }
303
304 static int vlclua_timer_delete( lua_State *L )
305 {
306     vlclua_timer_t **pp_timer = (vlclua_timer_t**)luaL_checkudata( L, 1, "timer" );
307     if( !pp_timer || !*pp_timer )
308         luaL_error( L, "Can't get pointer to timer" );
309
310     vlc_timer_destroy( (*pp_timer)->timer );
311     free( (*pp_timer)->psz_callback );
312     return 0;
313 }
314
315 static int vlclua_timer_create( lua_State *L )
316 {
317     vlclua_timer_t *p_timer = malloc( sizeof( vlclua_timer_t ) );
318     if( !lua_isstring( L, 1 ) )
319         return luaL_error( L, "timer(function_name)" );
320
321     if( vlc_timer_create( &p_timer->timer, vlclua_timer_callback, p_timer ) )
322         return luaL_error( L, "Cannot initialize the timer" );
323
324     p_timer->L = L;
325     p_timer->psz_callback = strdup( luaL_checkstring( L, 1 ) );
326
327     vlclua_timer_t **pp_timer = lua_newuserdata( L, sizeof( vlclua_timer_t* ) );
328     *pp_timer = p_timer;
329
330     /* Create the object */
331     if( luaL_newmetatable( L, "timer" ) )
332     {
333         lua_newtable( L );
334         luaL_register( L, NULL, vlclua_timer_reg );
335         lua_setfield( L, -2, "__index" );
336         lua_pushcfunction( L, vlclua_timer_delete );
337         lua_setfield( L, -2, "__gc" );
338     }
339     lua_setmetatable( L, -2 );
340
341     return 1;
342 }
343
344 /*****************************************************************************
345  *
346  *****************************************************************************/
347 static const luaL_Reg vlclua_misc_reg[] = {
348     { "version", vlclua_version },
349     { "copyright", vlclua_copyright },
350     { "license", vlclua_license },
351
352     { "datadir", vlclua_datadir },
353     { "userdatadir", vlclua_userdatadir },
354     { "homedir", vlclua_homedir },
355     { "configdir", vlclua_configdir },
356     { "cachedir", vlclua_cachedir },
357     { "datadir_list", vlclua_datadir_list },
358
359     { "action_id", vlclua_action_id },
360
361     { "mdate", vlclua_mdate },
362     { "mwait", vlclua_mwait },
363
364     { "lock_and_wait", vlclua_lock_and_wait },
365
366     { "should_die", vlclua_intf_should_die },
367     { "quit", vlclua_quit },
368
369     { "timer", vlclua_timer_create },
370
371     { NULL, NULL }
372 };
373
374 void luaopen_misc( lua_State *L )
375 {
376     lua_newtable( L );
377     luaL_register( L, NULL, vlclua_misc_reg );
378     lua_setfield( L, -2, "misc" );
379 }