]> git.sesse.net Git - vlc/blob - src/input/vlm.c
vlm: use vlc_object_alive()
[vlc] / src / input / vlm.c
1 /*****************************************************************************
2  * vlm.c: VLM interface plugin
3  *****************************************************************************
4  * Copyright (C) 2000-2005 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Simon Latapie <garf@videolan.org>
8  *          Laurent Aimar <fenrir@videolan.org>
9  *          Gildas Bazin <gbazin@videolan.org>
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  * Preamble
28  *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34
35 #include <stdio.h>
36 #include <ctype.h>                                              /* tolower() */
37 #include <assert.h>
38
39 #include <vlc_vlm.h>
40 #include <vlc_modules.h>
41
42 #ifndef WIN32
43 #   include <sys/time.h>                                   /* gettimeofday() */
44 #endif
45
46 #ifdef UNDER_CE
47 #include <sys/time.h>                                      /* gettimeofday() */
48 #endif
49
50 #include <time.h>                                                 /* ctime() */
51 #if defined (WIN32) && !defined (UNDER_CE)
52 #include <sys/timeb.h>                                            /* ftime() */
53 #endif
54 #include <limits.h>
55
56 #include <vlc_input.h>
57 #include <vlc_stream.h>
58 #include "vlm_internal.h"
59 #include "vlm_event.h"
60 #include <vlc_vod.h>
61 #include <vlc_sout.h>
62 #include <vlc_url.h>
63 #include "../stream_output/stream_output.h"
64 #include "../libvlc.h"
65
66 /*****************************************************************************
67  * Local prototypes.
68  *****************************************************************************/
69
70 static void* Manage( void * );
71 static int vlm_MediaVodControl( void *, vod_media_t *, const char *, int, va_list );
72
73 typedef struct preparse_data_t
74 {
75     vlc_sem_t *p_sem;
76     bool b_mux;
77 } preparse_data_t;
78
79 static int InputEventPreparse( vlc_object_t *p_this, char const *psz_cmd,
80                                vlc_value_t oldval, vlc_value_t newval, void *p_data )
81 {
82     VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
83     preparse_data_t *p_pre = p_data;
84
85     if( newval.i_int == INPUT_EVENT_DEAD ||
86         ( p_pre->b_mux && newval.i_int == INPUT_EVENT_ITEM_META ) )
87         vlc_sem_post( p_pre->p_sem );
88
89     return VLC_SUCCESS;
90 }
91
92 static int InputEvent( vlc_object_t *p_this, char const *psz_cmd,
93                        vlc_value_t oldval, vlc_value_t newval,
94                        void *p_data )
95 {
96     VLC_UNUSED(psz_cmd);
97     VLC_UNUSED(oldval);
98     input_thread_t *p_input = (input_thread_t *)p_this;
99     vlm_t *p_vlm = libvlc_priv( p_input->p_libvlc )->p_vlm;
100     assert( p_vlm );
101     vlm_media_sys_t *p_media = p_data;
102     const char *psz_instance_name = NULL;
103
104     if( newval.i_int == INPUT_EVENT_STATE )
105     {
106         for( int i = 0; i < p_media->i_instance; i++ )
107         {
108             if( p_media->instance[i]->p_input == p_input )
109             {
110                 psz_instance_name = p_media->instance[i]->psz_name;
111                 break;
112             }
113         }
114         vlm_SendEventMediaInstanceState( p_vlm, p_media->cfg.id, p_media->cfg.psz_name, psz_instance_name, var_GetInteger( p_input, "state" ) );
115
116         vlc_mutex_lock( &p_vlm->lock_manage );
117         p_vlm->input_state_changed = true;
118         vlc_cond_signal( &p_vlm->wait_manage );
119         vlc_mutex_unlock( &p_vlm->lock_manage );
120     }
121     return VLC_SUCCESS;
122 }
123
124 static vlc_mutex_t vlm_mutex = VLC_STATIC_MUTEX;
125
126 #undef vlm_New
127 /*****************************************************************************
128  * vlm_New:
129  *****************************************************************************/
130 vlm_t *vlm_New ( vlc_object_t *p_this )
131 {
132     vlm_t *p_vlm = NULL, **pp_vlm = &(libvlc_priv (p_this->p_libvlc)->p_vlm);
133     char *psz_vlmconf;
134
135     /* Avoid multiple creation */
136     vlc_mutex_lock( &vlm_mutex );
137
138     p_vlm = *pp_vlm;
139     if( p_vlm )
140     {   /* VLM already exists */
141         if( likely( p_vlm->users < UINT_MAX ) )
142             p_vlm->users++;
143         else
144             p_vlm = NULL;
145         vlc_mutex_unlock( &vlm_mutex );
146         return p_vlm;
147     }
148
149     msg_Dbg( p_this, "creating VLM" );
150
151     p_vlm = vlc_custom_create( p_this->p_libvlc, sizeof( *p_vlm ),
152                                "vlm daemon" );
153     if( !p_vlm )
154     {
155         vlc_mutex_unlock( &vlm_mutex );
156         return NULL;
157     }
158
159     vlc_mutex_init( &p_vlm->lock );
160     vlc_mutex_init( &p_vlm->lock_manage );
161     vlc_cond_init_daytime( &p_vlm->wait_manage );
162     p_vlm->users = 1;
163     p_vlm->input_state_changed = false;
164     p_vlm->i_id = 1;
165     TAB_INIT( p_vlm->i_media, p_vlm->media );
166     TAB_INIT( p_vlm->i_schedule, p_vlm->schedule );
167     p_vlm->p_vod = NULL;
168     var_Create( p_vlm, "intf-event", VLC_VAR_ADDRESS );
169
170     if( vlc_clone( &p_vlm->thread, Manage, p_vlm, VLC_THREAD_PRIORITY_LOW ) )
171     {
172         vlc_cond_destroy( &p_vlm->wait_manage );
173         vlc_mutex_destroy( &p_vlm->lock );
174         vlc_mutex_destroy( &p_vlm->lock_manage );
175         vlc_object_release( p_vlm );
176         vlc_mutex_unlock( &vlm_mutex );
177         return NULL;
178     }
179
180     *pp_vlm = p_vlm; /* for future reference */
181
182     /* Load our configuration file */
183     psz_vlmconf = var_CreateGetString( p_vlm, "vlm-conf" );
184     if( psz_vlmconf && *psz_vlmconf )
185     {
186         vlm_message_t *p_message = NULL;
187         char *psz_buffer = NULL;
188
189         msg_Dbg( p_this, "loading VLM configuration" );
190         if( asprintf(&psz_buffer, "load %s", psz_vlmconf ) != -1 )
191         {
192             msg_Dbg( p_this, "%s", psz_buffer );
193             if( vlm_ExecuteCommand( p_vlm, psz_buffer, &p_message ) )
194                 msg_Warn( p_this, "error while loading the configuration file" );
195
196             vlm_MessageDelete( p_message );
197             free( psz_buffer );
198         }
199     }
200     free( psz_vlmconf );
201
202     vlc_mutex_unlock( &vlm_mutex );
203
204     return p_vlm;
205 }
206
207 /*****************************************************************************
208  * vlm_Delete:
209  *****************************************************************************/
210 void vlm_Delete( vlm_t *p_vlm )
211 {
212     /* vlm_Delete() is serialized against itself, and against vlm_New().
213      * This mutex protects libvlc_priv->p_vlm and p_vlm->users. */
214     vlc_mutex_lock( &vlm_mutex );
215     assert( p_vlm->users > 0 );
216     if( --p_vlm->users == 0 )
217         assert( libvlc_priv(p_vlm->p_libvlc)->p_vlm == p_vlm );
218     else
219         p_vlm = NULL;
220
221     if( p_vlm == NULL )
222     {
223         vlc_mutex_unlock( &vlm_mutex );
224         return;
225     }
226
227     /* Destroy and release VLM */
228     vlc_mutex_lock( &p_vlm->lock );
229     vlm_ControlInternal( p_vlm, VLM_CLEAR_MEDIAS );
230     TAB_CLEAN( p_vlm->i_media, p_vlm->media );
231
232     vlm_ControlInternal( p_vlm, VLM_CLEAR_SCHEDULES );
233     TAB_CLEAN( p_vlm->i_schedule, p_vlm->schedule );
234     vlc_mutex_unlock( &p_vlm->lock );
235
236     vlc_object_kill( p_vlm );
237
238     if( p_vlm->p_vod )
239     {
240         module_unneed( p_vlm->p_vod, p_vlm->p_vod->p_module );
241         vlc_object_release( p_vlm->p_vod );
242     }
243
244     libvlc_priv(p_vlm->p_libvlc)->p_vlm = NULL;
245     vlc_mutex_unlock( &vlm_mutex );
246
247     vlc_mutex_lock( &p_vlm->lock_manage );
248     p_vlm->input_state_changed = true;
249     vlc_cond_signal( &p_vlm->wait_manage );
250     vlc_mutex_unlock( &p_vlm->lock_manage );
251
252     /*vlc_cancel( p_vlm->thread ); */
253     vlc_join( p_vlm->thread, NULL );
254
255     vlc_cond_destroy( &p_vlm->wait_manage );
256     vlc_mutex_destroy( &p_vlm->lock );
257     vlc_mutex_destroy( &p_vlm->lock_manage );
258     vlc_object_release( p_vlm );
259 }
260
261 /*****************************************************************************
262  * vlm_ExecuteCommand:
263  *****************************************************************************/
264 int vlm_ExecuteCommand( vlm_t *p_vlm, const char *psz_command,
265                         vlm_message_t **pp_message)
266 {
267     int i_result;
268
269     vlc_mutex_lock( &p_vlm->lock );
270     i_result = ExecuteCommand( p_vlm, psz_command, pp_message );
271     vlc_mutex_unlock( &p_vlm->lock );
272
273     return i_result;
274 }
275
276
277 int64_t vlm_Date(void)
278 {
279 #if defined (WIN32) && !defined (UNDER_CE)
280     struct timeb tm;
281     ftime( &tm );
282     return ((int64_t)tm.time) * 1000000 + ((int64_t)tm.millitm) * 1000;
283 #else
284     struct timeval tv_date;
285
286     /* gettimeofday() cannot fail given &tv_date is a valid address */
287     (void)gettimeofday( &tv_date, NULL );
288     return (mtime_t) tv_date.tv_sec * 1000000 + (mtime_t) tv_date.tv_usec;
289 #endif
290 }
291
292
293 /*****************************************************************************
294  *
295  *****************************************************************************/
296 static int vlm_MediaVodControl( void *p_private, vod_media_t *p_vod_media,
297                                 const char *psz_id, int i_query, va_list args )
298 {
299     vlm_t *vlm = (vlm_t *)p_private;
300     int i, i_ret;
301     const char *psz;
302     int64_t id;
303
304     if( !p_private || !p_vod_media )
305         return VLC_EGENERIC;
306
307     vlc_mutex_lock( &vlm->lock );
308
309     /* Find media id */
310     for( i = 0, id = -1; i < vlm->i_media; i++ )
311     {
312         if( p_vod_media == vlm->media[i]->vod.p_media )
313         {
314             id = vlm->media[i]->cfg.id;
315             break;
316         }
317     }
318     if( id == -1 )
319     {
320         vlc_mutex_unlock( &vlm->lock );
321         return VLC_EGENERIC;
322     }
323
324     switch( i_query )
325     {
326     case VOD_MEDIA_PLAY:
327     {
328         psz = (const char *)va_arg( args, const char * );
329         int64_t *i_time = (int64_t *)va_arg( args, int64_t *);
330         bool b_retry = false;
331         if (*i_time < 0)
332         {
333             /* No start time requested: return the current NPT */
334             i_ret = vlm_ControlInternal( vlm, VLM_GET_MEDIA_INSTANCE_TIME, id, psz_id, i_time );
335             /* The instance is not running yet, it will start at 0 */
336             if (i_ret)
337                 *i_time = 0;
338         }
339         else
340         {
341             /* We want to seek before unpausing, but it won't
342              * work if the instance is not running yet. */
343             b_retry = vlm_ControlInternal( vlm, VLM_SET_MEDIA_INSTANCE_TIME, id, psz_id, *i_time );
344         }
345
346         i_ret = vlm_ControlInternal( vlm, VLM_START_MEDIA_VOD_INSTANCE, id, psz_id, 0, psz );
347
348         if (!i_ret && b_retry)
349             i_ret = vlm_ControlInternal( vlm, VLM_SET_MEDIA_INSTANCE_TIME, id, psz_id, *i_time );
350         break;
351     }
352
353     case VOD_MEDIA_PAUSE:
354     {
355         int64_t *i_time = (int64_t *)va_arg( args, int64_t *);
356         i_ret = vlm_ControlInternal( vlm, VLM_PAUSE_MEDIA_INSTANCE, id, psz_id );
357         if (!i_ret)
358             i_ret = vlm_ControlInternal( vlm, VLM_GET_MEDIA_INSTANCE_TIME, id, psz_id, i_time );
359         break;
360     }
361
362     case VOD_MEDIA_STOP:
363         i_ret = vlm_ControlInternal( vlm, VLM_STOP_MEDIA_INSTANCE, id, psz_id );
364         break;
365
366     case VOD_MEDIA_SEEK:
367     {
368         int64_t i_time = (int64_t)va_arg( args, int64_t );
369         i_ret = vlm_ControlInternal( vlm, VLM_SET_MEDIA_INSTANCE_TIME, id, psz_id, i_time );
370         break;
371     }
372
373     case VOD_MEDIA_REWIND:
374     {
375         double d_scale = (double)va_arg( args, double );
376         double d_position;
377
378         vlm_ControlInternal( vlm, VLM_GET_MEDIA_INSTANCE_POSITION, id, psz_id, &d_position );
379         d_position -= (d_scale / 1000.0);
380         if( d_position < 0.0 )
381             d_position = 0.0;
382         i_ret = vlm_ControlInternal( vlm, VLM_SET_MEDIA_INSTANCE_POSITION, id, psz_id, d_position );
383         break;
384     }
385
386     case VOD_MEDIA_FORWARD:
387     {
388         double d_scale = (double)va_arg( args, double );
389         double d_position;
390
391         vlm_ControlInternal( vlm, VLM_GET_MEDIA_INSTANCE_POSITION, id, psz_id, &d_position );
392         d_position += (d_scale / 1000.0);
393         if( d_position > 1.0 )
394             d_position = 1.0;
395         i_ret = vlm_ControlInternal( vlm, VLM_SET_MEDIA_INSTANCE_POSITION, id, psz_id, d_position );
396         break;
397     }
398
399     default:
400         i_ret = VLC_EGENERIC;
401         break;
402     }
403
404     vlc_mutex_unlock( &vlm->lock );
405
406     return i_ret;
407 }
408
409
410 /*****************************************************************************
411  * Manage:
412  *****************************************************************************/
413 static void* Manage( void* p_object )
414 {
415     vlm_t *vlm = (vlm_t*)p_object;
416     int i, j;
417     mtime_t i_lastcheck;
418     mtime_t i_time;
419     mtime_t i_nextschedule = 0;
420
421     int canc = vlc_savecancel ();
422     i_lastcheck = vlm_Date();
423
424     while( vlc_object_alive( vlm ) )
425     {
426         char **ppsz_scheduled_commands = NULL;
427         int    i_scheduled_commands = 0;
428         bool scheduled_command = false;
429
430         vlc_mutex_lock( &vlm->lock_manage );
431         while( !vlm->input_state_changed && !scheduled_command )
432         {
433             if( i_nextschedule )
434                 scheduled_command = vlc_cond_timedwait( &vlm->wait_manage, &vlm->lock_manage, i_nextschedule ) != 0;
435             else
436                 vlc_cond_wait( &vlm->wait_manage, &vlm->lock_manage );
437         }
438         vlm->input_state_changed = false;
439         vlc_mutex_unlock( &vlm->lock_manage );
440         /* destroy the inputs that wants to die, and launch the next input */
441         vlc_mutex_lock( &vlm->lock );
442         for( i = 0; i < vlm->i_media; i++ )
443         {
444             vlm_media_sys_t *p_media = vlm->media[i];
445
446             for( j = 0; j < p_media->i_instance; )
447             {
448                 vlm_media_instance_sys_t *p_instance = p_media->instance[j];
449
450                 if( p_instance->p_input && ( p_instance->p_input->b_eof || p_instance->p_input->b_error ) )
451                 {
452                     int i_new_input_index;
453
454                     /* */
455                     i_new_input_index = p_instance->i_index + 1;
456                     if( !p_media->cfg.b_vod && p_media->cfg.broadcast.b_loop && i_new_input_index >= p_media->cfg.i_input )
457                         i_new_input_index = 0;
458
459                     /* FIXME implement multiple input with VOD */
460                     if( p_media->cfg.b_vod || i_new_input_index >= p_media->cfg.i_input )
461                         vlm_ControlInternal( vlm, VLM_STOP_MEDIA_INSTANCE, p_media->cfg.id, p_instance->psz_name );
462                     else
463                         vlm_ControlInternal( vlm, VLM_START_MEDIA_BROADCAST_INSTANCE, p_media->cfg.id, p_instance->psz_name, i_new_input_index );
464
465                     j = 0;
466                 }
467                 else
468                 {
469                     j++;
470                 }
471             }
472         }
473
474         /* scheduling */
475         i_time = vlm_Date();
476         i_nextschedule = 0;
477
478         for( i = 0; i < vlm->i_schedule; i++ )
479         {
480             mtime_t i_real_date = vlm->schedule[i]->i_date;
481
482             if( vlm->schedule[i]->b_enabled )
483             {
484                 if( vlm->schedule[i]->i_date == 0 ) // now !
485                 {
486                     vlm->schedule[i]->i_date = (i_time / 1000000) * 1000000 ;
487                     i_real_date = i_time;
488                 }
489                 else if( vlm->schedule[i]->i_period != 0 )
490                 {
491                     int j = 0;
492                     while( vlm->schedule[i]->i_date + j *
493                            vlm->schedule[i]->i_period <= i_lastcheck &&
494                            ( vlm->schedule[i]->i_repeat > j ||
495                              vlm->schedule[i]->i_repeat == -1 ) )
496                     {
497                         j++;
498                     }
499
500                     i_real_date = vlm->schedule[i]->i_date + j *
501                         vlm->schedule[i]->i_period;
502                 }
503
504                 if( i_real_date <= i_time )
505                 {
506                     if( i_real_date > i_lastcheck )
507                     {
508                         for( j = 0; j < vlm->schedule[i]->i_command; j++ )
509                         {
510                             TAB_APPEND( i_scheduled_commands,
511                                         ppsz_scheduled_commands,
512                                         strdup(vlm->schedule[i]->command[j] ) );
513                         }
514                     }
515                 }
516                 else if( i_nextschedule == 0 || i_real_date < i_nextschedule )
517                 {
518                     i_nextschedule = i_real_date;
519                 }
520             }
521         }
522
523         while( i_scheduled_commands )
524         {
525             vlm_message_t *message = NULL;
526             char *psz_command = ppsz_scheduled_commands[0];
527             ExecuteCommand( vlm, psz_command,&message );
528
529             /* for now, drop the message */
530             vlm_MessageDelete( message );
531             TAB_REMOVE( i_scheduled_commands,
532                         ppsz_scheduled_commands,
533                         psz_command );
534             free( psz_command );
535         }
536
537         i_lastcheck = i_time;
538         vlc_mutex_unlock( &vlm->lock );
539
540     }
541
542     vlc_restorecancel (canc);
543     return NULL;
544 }
545
546 /* New API
547  */
548 /*
549 typedef struct
550 {
551     struct
552     {
553         int i_connection_count;
554         int i_connection_active;
555     } vod;
556     struct
557     {
558         int        i_count;
559         bool b_playing;
560         int        i_playing_index;
561     } broadcast;
562
563 } vlm_media_status_t;
564 */
565
566 /* */
567 static vlm_media_sys_t *vlm_ControlMediaGetById( vlm_t *p_vlm, int64_t id )
568 {
569     int i;
570
571     for( i = 0; i < p_vlm->i_media; i++ )
572     {
573         if( p_vlm->media[i]->cfg.id == id )
574             return p_vlm->media[i];
575     }
576     return NULL;
577 }
578 static vlm_media_sys_t *vlm_ControlMediaGetByName( vlm_t *p_vlm, const char *psz_name )
579 {
580     int i;
581
582     for( i = 0; i < p_vlm->i_media; i++ )
583     {
584         if( !strcmp( p_vlm->media[i]->cfg.psz_name, psz_name ) )
585             return p_vlm->media[i];
586     }
587     return NULL;
588 }
589 static int vlm_MediaDescriptionCheck( vlm_t *p_vlm, vlm_media_t *p_cfg )
590 {
591     int i;
592
593     if( !p_cfg || !p_cfg->psz_name ||
594         !strcmp( p_cfg->psz_name, "all" ) || !strcmp( p_cfg->psz_name, "media" ) || !strcmp( p_cfg->psz_name, "schedule" ) )
595         return VLC_EGENERIC;
596
597     for( i = 0; i < p_vlm->i_media; i++ )
598     {
599         if( p_vlm->media[i]->cfg.id == p_cfg->id )
600             continue;
601         if( !strcmp( p_vlm->media[i]->cfg.psz_name, p_cfg->psz_name ) )
602             return VLC_EGENERIC;
603     }
604     return VLC_SUCCESS;
605 }
606
607
608 /* Called after a media description is changed/added */
609 static int vlm_OnMediaUpdate( vlm_t *p_vlm, vlm_media_sys_t *p_media )
610 {
611     vlm_media_t *p_cfg = &p_media->cfg;
612     /* Check if we need to create/delete a vod media */
613     if( p_cfg->b_vod && p_vlm->p_vod )
614     {
615         if( !p_cfg->b_enabled && p_media->vod.p_media )
616         {
617             p_vlm->p_vod->pf_media_del( p_vlm->p_vod, p_media->vod.p_media );
618             p_media->vod.p_media = NULL;
619         }
620         else if( p_cfg->b_enabled && !p_media->vod.p_media && p_cfg->i_input )
621         {
622             /* Pre-parse the input */
623             input_thread_t *p_input;
624             char *psz_output;
625             char *psz_header;
626             char *psz_dup;
627             int i;
628
629             vlc_gc_decref( p_media->vod.p_item );
630
631             char *psz_uri = make_URI( p_cfg->ppsz_input[0], NULL );
632             p_media->vod.p_item = input_item_New( psz_uri, p_cfg->psz_name );
633             free( psz_uri );
634
635             if( p_cfg->psz_output )
636             {
637                 if( asprintf( &psz_output, "%s:description", p_cfg->psz_output )  == -1 )
638                     psz_output = NULL;
639             }
640             else
641                 psz_output = strdup( "#description" );
642
643             if( psz_output && asprintf( &psz_dup, "sout=%s", psz_output ) != -1 )
644             {
645                 input_item_AddOption( p_media->vod.p_item, psz_dup, VLC_INPUT_OPTION_TRUSTED );
646                 free( psz_dup );
647             }
648             free( psz_output );
649
650             for( i = 0; i < p_cfg->i_option; i++ )
651                 input_item_AddOption( p_media->vod.p_item,
652                                       p_cfg->ppsz_option[i], VLC_INPUT_OPTION_TRUSTED );
653
654             if( asprintf( &psz_header, _("Media: %s"), p_cfg->psz_name ) == -1 )
655                 psz_header = NULL;
656
657             sout_description_data_t data;
658             TAB_INIT(data.i_es, data.es);
659
660             p_input = input_Create( p_vlm->p_vod, p_media->vod.p_item, psz_header, NULL );
661             if( p_input )
662             {
663                 vlc_sem_t sem_preparse;
664                 vlc_sem_init( &sem_preparse, 0 );
665
666                 preparse_data_t preparse = { .p_sem = &sem_preparse,
667                                     .b_mux = (p_cfg->vod.psz_mux != NULL) };
668                 var_AddCallback( p_input, "intf-event", InputEventPreparse,
669                                  &preparse );
670
671                 data.sem = &sem_preparse;
672                 var_Create( p_input, "sout-description-data", VLC_VAR_ADDRESS );
673                 var_SetAddress( p_input, "sout-description-data", &data );
674
675                 if( !input_Start( p_input ) )
676                     vlc_sem_wait( &sem_preparse );
677
678                 var_DelCallback( p_input, "intf-event", InputEventPreparse,
679                                  &preparse );
680
681                 input_Stop( p_input, true );
682                 input_Close( p_input );
683                 vlc_sem_destroy( &sem_preparse );
684             }
685             free( psz_header );
686
687             /* XXX: Don't do it that way, but properly use a new input item ref. */
688             input_item_t item = *p_media->vod.p_item;;
689             if( p_cfg->vod.psz_mux )
690             {
691                 const char *psz_mux;
692                 if (!strcmp(p_cfg->vod.psz_mux, "ps"))
693                     psz_mux = "mp2p";
694                 else if (!strcmp(p_cfg->vod.psz_mux, "ts"))
695                     psz_mux = "mp2t";
696                 else
697                     psz_mux = p_cfg->vod.psz_mux;
698
699                 es_format_t es, *p_es = &es;
700                 union {
701                     char text[5];
702                     unsigned char utext[5];
703                     uint32_t value;
704                 } fourcc;
705
706                 sprintf( fourcc.text, "%4.4s", psz_mux );
707                 for( int i = 0; i < 4; i++ )
708                     fourcc.utext[i] = tolower(fourcc.utext[i]);
709
710                 item.i_es = 1;
711                 item.es = &p_es;
712                 es_format_Init( &es, VIDEO_ES, fourcc.value );
713             }
714             else
715             {
716                 item.i_es = data.i_es;
717                 item.es = data.es;
718             }
719             p_media->vod.p_media = p_vlm->p_vod->pf_media_new( p_vlm->p_vod,
720                                                     p_cfg->psz_name, &item );
721
722             TAB_CLEAN(data.i_es, data.es);
723         }
724     }
725     else if ( p_cfg->b_vod )
726         msg_Err( p_vlm, "vod server is not loaded" );
727     else
728     {
729         /* TODO start media if needed */
730     }
731
732     /* TODO add support of var vlm_media_broadcast/vlm_media_vod */
733
734     vlm_SendEventMediaChanged( p_vlm, p_cfg->id, p_cfg->psz_name );
735     return VLC_SUCCESS;
736 }
737 static int vlm_ControlMediaChange( vlm_t *p_vlm, vlm_media_t *p_cfg )
738 {
739     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, p_cfg->id );
740
741     /* */
742     if( !p_media || vlm_MediaDescriptionCheck( p_vlm, p_cfg ) )
743         return VLC_EGENERIC;
744     if( ( p_media->cfg.b_vod && !p_cfg->b_vod ) || ( !p_media->cfg.b_vod && p_cfg->b_vod ) )
745         return VLC_EGENERIC;
746
747     if( 0 )
748     {
749         /* TODO check what are the changes being done (stop instance if needed) */
750     }
751
752     vlm_media_Clean( &p_media->cfg );
753     vlm_media_Copy( &p_media->cfg, p_cfg );
754
755     return vlm_OnMediaUpdate( p_vlm, p_media );
756 }
757
758 static int vlm_ControlMediaAdd( vlm_t *p_vlm, vlm_media_t *p_cfg, int64_t *p_id )
759 {
760     vlm_media_sys_t *p_media;
761
762     if( vlm_MediaDescriptionCheck( p_vlm, p_cfg ) || vlm_ControlMediaGetByName( p_vlm, p_cfg->psz_name ) )
763     {
764         msg_Err( p_vlm, "invalid media description" );
765         return VLC_EGENERIC;
766     }
767     /* Check if we need to load the VOD server */
768     if( p_cfg->b_vod && !p_vlm->p_vod )
769     {
770         p_vlm->p_vod = vlc_custom_create( VLC_OBJECT(p_vlm), sizeof( vod_t ),
771                                           "vod server" );
772         p_vlm->p_vod->p_module = module_need( p_vlm->p_vod, "vod server", "$vod-server", false );
773         if( !p_vlm->p_vod->p_module )
774         {
775             msg_Err( p_vlm, "cannot find vod server" );
776             vlc_object_release( p_vlm->p_vod );
777             p_vlm->p_vod = NULL;
778             return VLC_EGENERIC;
779         }
780
781         p_vlm->p_vod->p_data = p_vlm;
782         p_vlm->p_vod->pf_media_control = vlm_MediaVodControl;
783     }
784
785     p_media = calloc( 1, sizeof( vlm_media_sys_t ) );
786     if( !p_media )
787         return VLC_ENOMEM;
788
789     vlm_media_Copy( &p_media->cfg, p_cfg );
790     p_media->cfg.id = p_vlm->i_id++;
791     /* FIXME do we do something here if enabled is true ? */
792
793     p_media->vod.p_item = input_item_New( NULL, NULL );
794
795     p_media->vod.p_media = NULL;
796     TAB_INIT( p_media->i_instance, p_media->instance );
797
798     /* */
799     TAB_APPEND( p_vlm->i_media, p_vlm->media, p_media );
800
801     if( p_id )
802         *p_id = p_media->cfg.id;
803
804     /* */
805     vlm_SendEventMediaAdded( p_vlm, p_media->cfg.id, p_media->cfg.psz_name );
806     return vlm_OnMediaUpdate( p_vlm, p_media );
807 }
808
809 static int vlm_ControlMediaDel( vlm_t *p_vlm, int64_t id )
810 {
811     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
812
813     if( !p_media )
814         return VLC_EGENERIC;
815
816     while( p_media->i_instance > 0 )
817         vlm_ControlInternal( p_vlm, VLM_STOP_MEDIA_INSTANCE, id, p_media->instance[0]->psz_name );
818
819     if( p_media->cfg.b_vod )
820     {
821         p_media->cfg.b_enabled = false;
822         vlm_OnMediaUpdate( p_vlm, p_media );
823     }
824
825     /* */
826     vlm_SendEventMediaRemoved( p_vlm, id, p_media->cfg.psz_name );
827
828     vlm_media_Clean( &p_media->cfg );
829
830     vlc_gc_decref( p_media->vod.p_item );
831
832     if( p_media->vod.p_media )
833         p_vlm->p_vod->pf_media_del( p_vlm->p_vod, p_media->vod.p_media );
834
835     TAB_REMOVE( p_vlm->i_media, p_vlm->media, p_media );
836     free( p_media );
837
838     return VLC_SUCCESS;
839 }
840
841 static int vlm_ControlMediaGets( vlm_t *p_vlm, vlm_media_t ***ppp_dsc, int *pi_dsc )
842 {
843     vlm_media_t **pp_dsc;
844     int                     i_dsc;
845     int i;
846
847     TAB_INIT( i_dsc, pp_dsc );
848     for( i = 0; i < p_vlm->i_media; i++ )
849     {
850         vlm_media_t *p_dsc = vlm_media_Duplicate( &p_vlm->media[i]->cfg );
851         TAB_APPEND( i_dsc, pp_dsc, p_dsc );
852     }
853
854     *ppp_dsc = pp_dsc;
855     *pi_dsc = i_dsc;
856
857     return VLC_SUCCESS;
858 }
859 static int vlm_ControlMediaClear( vlm_t *p_vlm )
860 {
861     while( p_vlm->i_media > 0 )
862         vlm_ControlMediaDel( p_vlm, p_vlm->media[0]->cfg.id );
863
864     return VLC_SUCCESS;
865 }
866 static int vlm_ControlMediaGet( vlm_t *p_vlm, int64_t id, vlm_media_t **pp_dsc )
867 {
868     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
869     if( !p_media )
870         return VLC_EGENERIC;
871
872     *pp_dsc = vlm_media_Duplicate( &p_media->cfg );
873     return VLC_SUCCESS;
874 }
875 static int vlm_ControlMediaGetId( vlm_t *p_vlm, const char *psz_name, int64_t *p_id )
876 {
877     vlm_media_sys_t *p_media = vlm_ControlMediaGetByName( p_vlm, psz_name );
878     if( !p_media )
879         return VLC_EGENERIC;
880
881     *p_id = p_media->cfg.id;
882     return VLC_SUCCESS;
883 }
884
885 static vlm_media_instance_sys_t *vlm_ControlMediaInstanceGetByName( vlm_media_sys_t *p_media, const char *psz_id )
886 {
887     int i;
888
889     for( i = 0; i < p_media->i_instance; i++ )
890     {
891         const char *psz = p_media->instance[i]->psz_name;
892         if( ( psz == NULL && psz_id == NULL ) ||
893             ( psz && psz_id && !strcmp( psz, psz_id ) ) )
894             return p_media->instance[i];
895     }
896     return NULL;
897 }
898 static vlm_media_instance_sys_t *vlm_MediaInstanceNew( vlm_t *p_vlm, const char *psz_name )
899 {
900     vlm_media_instance_sys_t *p_instance = calloc( 1, sizeof(vlm_media_instance_sys_t) );
901     if( !p_instance )
902         return NULL;
903
904     p_instance->psz_name = NULL;
905     if( psz_name )
906         p_instance->psz_name = strdup( psz_name );
907
908     p_instance->p_item = input_item_New( NULL, NULL );
909
910     p_instance->i_index = 0;
911     p_instance->b_sout_keep = false;
912     p_instance->p_parent = vlc_object_create( p_vlm, sizeof (vlc_object_t) );
913     p_instance->p_input = NULL;
914     p_instance->p_input_resource = NULL;
915
916     return p_instance;
917 }
918 static void vlm_MediaInstanceDelete( vlm_t *p_vlm, int64_t id, vlm_media_instance_sys_t *p_instance, vlm_media_sys_t *p_media )
919 {
920     input_thread_t *p_input = p_instance->p_input;
921     if( p_input )
922     {
923         input_Stop( p_input, true );
924         input_Join( p_input );
925         var_DelCallback( p_instance->p_input, "intf-event", InputEvent, p_media );
926         input_Release( p_input );
927
928         vlm_SendEventMediaInstanceStopped( p_vlm, id, p_media->cfg.psz_name );
929     }
930     if( p_instance->p_input_resource )
931     {
932         input_resource_Terminate( p_instance->p_input_resource );
933         input_resource_Release( p_instance->p_input_resource );
934     }
935     vlc_object_release( p_instance->p_parent );
936
937     TAB_REMOVE( p_media->i_instance, p_media->instance, p_instance );
938     vlc_gc_decref( p_instance->p_item );
939     free( p_instance->psz_name );
940     free( p_instance );
941 }
942
943
944 static int vlm_ControlMediaInstanceStart( vlm_t *p_vlm, int64_t id, const char *psz_id, int i_input_index, const char *psz_vod_output )
945 {
946     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
947     vlm_media_instance_sys_t *p_instance;
948     char *psz_log;
949
950     if( !p_media || !p_media->cfg.b_enabled || p_media->cfg.i_input <= 0 )
951         return VLC_EGENERIC;
952
953     /* TODO support multiple input for VOD with sout-keep ? */
954
955     if( ( p_media->cfg.b_vod && !psz_vod_output ) || ( !p_media->cfg.b_vod && psz_vod_output ) )
956         return VLC_EGENERIC;
957
958     if( i_input_index < 0 || i_input_index >= p_media->cfg.i_input )
959         return VLC_EGENERIC;
960
961     p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
962     if( !p_instance )
963     {
964         vlm_media_t *p_cfg = &p_media->cfg;
965         int i;
966
967         p_instance = vlm_MediaInstanceNew( p_vlm, psz_id );
968         if( !p_instance )
969             return VLC_ENOMEM;
970
971         if ( p_cfg->b_vod )
972         {
973             var_Create( p_instance->p_parent, "vod-media", VLC_VAR_ADDRESS );
974             var_SetAddress( p_instance->p_parent, "vod-media",
975                             p_media->vod.p_media );
976             var_Create( p_instance->p_parent, "vod-session", VLC_VAR_STRING );
977             var_SetString( p_instance->p_parent, "vod-session", psz_id );
978         }
979
980         if( p_cfg->psz_output != NULL || psz_vod_output != NULL )
981         {
982             char *psz_buffer;
983             if( asprintf( &psz_buffer, "sout=%s%s%s",
984                       p_cfg->psz_output ? p_cfg->psz_output : "",
985                       (p_cfg->psz_output && psz_vod_output) ? ":" : psz_vod_output ? "#" : "",
986                       psz_vod_output ? psz_vod_output : "" ) != -1 )
987             {
988                 input_item_AddOption( p_instance->p_item, psz_buffer, VLC_INPUT_OPTION_TRUSTED );
989                 free( psz_buffer );
990             }
991         }
992
993         for( i = 0; i < p_cfg->i_option; i++ )
994         {
995             if( !strcmp( p_cfg->ppsz_option[i], "sout-keep" ) )
996                 p_instance->b_sout_keep = true;
997             else if( !strcmp( p_cfg->ppsz_option[i], "nosout-keep" ) || !strcmp( p_cfg->ppsz_option[i], "no-sout-keep" ) )
998                 p_instance->b_sout_keep = false;
999             else
1000                 input_item_AddOption( p_instance->p_item, p_cfg->ppsz_option[i], VLC_INPUT_OPTION_TRUSTED );
1001         }
1002         TAB_APPEND( p_media->i_instance, p_media->instance, p_instance );
1003     }
1004
1005     /* Stop old instance */
1006     input_thread_t *p_input = p_instance->p_input;
1007     if( p_input )
1008     {
1009         if( p_instance->i_index == i_input_index &&
1010             !p_input->b_eof && !p_input->b_error )
1011         {
1012             if( var_GetInteger( p_input, "state" ) == PAUSE_S )
1013                 var_SetInteger( p_input, "state",  PLAYING_S );
1014             return VLC_SUCCESS;
1015         }
1016
1017
1018         input_Stop( p_input, true );
1019         input_Join( p_input );
1020         var_DelCallback( p_instance->p_input, "intf-event", InputEvent, p_media );
1021         input_Release( p_input );
1022
1023         if( !p_instance->b_sout_keep )
1024             input_resource_TerminateSout( p_instance->p_input_resource );
1025         input_resource_TerminateVout( p_instance->p_input_resource );
1026
1027         vlm_SendEventMediaInstanceStopped( p_vlm, id, p_media->cfg.psz_name );
1028     }
1029
1030     /* Start new one */
1031     p_instance->i_index = i_input_index;
1032     char *psz_uri = make_URI( p_media->cfg.ppsz_input[p_instance->i_index],
1033                               NULL );
1034     input_item_SetURI( p_instance->p_item, psz_uri ) ;
1035     free( psz_uri );
1036
1037     if( asprintf( &psz_log, _("Media: %s"), p_media->cfg.psz_name ) != -1 )
1038     {
1039         if( !p_instance->p_input_resource )
1040             p_instance->p_input_resource = input_resource_New( p_instance->p_parent );
1041
1042         p_instance->p_input = input_Create( p_instance->p_parent,
1043                                             p_instance->p_item, psz_log,
1044                                             p_instance->p_input_resource );
1045         if( p_instance->p_input )
1046         {
1047             var_AddCallback( p_instance->p_input, "intf-event", InputEvent, p_media );
1048
1049             if( input_Start( p_instance->p_input ) != VLC_SUCCESS )
1050             {
1051                 var_DelCallback( p_instance->p_input, "intf-event", InputEvent, p_media );
1052                 vlc_object_release( p_instance->p_input );
1053                 p_instance->p_input = NULL;
1054             }
1055         }
1056
1057         if( !p_instance->p_input )
1058         {
1059             vlm_MediaInstanceDelete( p_vlm, id, p_instance, p_media );
1060         }
1061         else
1062         {
1063             vlm_SendEventMediaInstanceStarted( p_vlm, id, p_media->cfg.psz_name );
1064         }
1065         free( psz_log );
1066     }
1067
1068     return VLC_SUCCESS;
1069 }
1070
1071 static int vlm_ControlMediaInstanceStop( vlm_t *p_vlm, int64_t id, const char *psz_id )
1072 {
1073     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
1074     vlm_media_instance_sys_t *p_instance;
1075
1076     if( !p_media )
1077         return VLC_EGENERIC;
1078
1079     p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
1080     if( !p_instance )
1081         return VLC_EGENERIC;
1082
1083     vlm_MediaInstanceDelete( p_vlm, id, p_instance, p_media );
1084
1085     return VLC_SUCCESS;
1086 }
1087 static int vlm_ControlMediaInstancePause( vlm_t *p_vlm, int64_t id, const char *psz_id )
1088 {
1089     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
1090     vlm_media_instance_sys_t *p_instance;
1091     int i_state;
1092
1093     if( !p_media )
1094         return VLC_EGENERIC;
1095
1096     p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
1097     if( !p_instance || !p_instance->p_input )
1098         return VLC_EGENERIC;
1099
1100     /* Toggle pause state */
1101     i_state = var_GetInteger( p_instance->p_input, "state" );
1102     if( i_state == PAUSE_S && !p_media->cfg.b_vod )
1103         var_SetInteger( p_instance->p_input, "state", PLAYING_S );
1104     else if( i_state == PLAYING_S )
1105         var_SetInteger( p_instance->p_input, "state", PAUSE_S );
1106     return VLC_SUCCESS;
1107 }
1108 static int vlm_ControlMediaInstanceGetTimePosition( vlm_t *p_vlm, int64_t id, const char *psz_id, int64_t *pi_time, double *pd_position )
1109 {
1110     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
1111     vlm_media_instance_sys_t *p_instance;
1112
1113     if( !p_media )
1114         return VLC_EGENERIC;
1115
1116     p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
1117     if( !p_instance || !p_instance->p_input )
1118         return VLC_EGENERIC;
1119
1120     if( pi_time )
1121         *pi_time = var_GetTime( p_instance->p_input, "time" );
1122     if( pd_position )
1123         *pd_position = var_GetFloat( p_instance->p_input, "position" );
1124     return VLC_SUCCESS;
1125 }
1126 static int vlm_ControlMediaInstanceSetTimePosition( vlm_t *p_vlm, int64_t id, const char *psz_id, int64_t i_time, double d_position )
1127 {
1128     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
1129     vlm_media_instance_sys_t *p_instance;
1130
1131     if( !p_media )
1132         return VLC_EGENERIC;
1133
1134     p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
1135     if( !p_instance || !p_instance->p_input )
1136         return VLC_EGENERIC;
1137
1138     if( i_time >= 0 )
1139         return var_SetTime( p_instance->p_input, "time", i_time );
1140     else if( d_position >= 0 && d_position <= 100 )
1141         return var_SetFloat( p_instance->p_input, "position", d_position );
1142     return VLC_EGENERIC;
1143 }
1144
1145 static int vlm_ControlMediaInstanceGets( vlm_t *p_vlm, int64_t id, vlm_media_instance_t ***ppp_idsc, int *pi_instance )
1146 {
1147     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
1148     vlm_media_instance_t **pp_idsc;
1149     int                              i_idsc;
1150     int i;
1151
1152     if( !p_media )
1153         return VLC_EGENERIC;
1154
1155     TAB_INIT( i_idsc, pp_idsc );
1156     for( i = 0; i < p_media->i_instance; i++ )
1157     {
1158         vlm_media_instance_sys_t *p_instance = p_media->instance[i];
1159         vlm_media_instance_t *p_idsc = vlm_media_instance_New();
1160
1161         if( p_instance->psz_name )
1162             p_idsc->psz_name = strdup( p_instance->psz_name );
1163         if( p_instance->p_input )
1164         {
1165             p_idsc->i_time = var_GetTime( p_instance->p_input, "time" );
1166             p_idsc->i_length = var_GetTime( p_instance->p_input, "length" );
1167             p_idsc->d_position = var_GetFloat( p_instance->p_input, "position" );
1168             if( var_GetInteger( p_instance->p_input, "state" ) == PAUSE_S )
1169                 p_idsc->b_paused = true;
1170             p_idsc->i_rate = INPUT_RATE_DEFAULT
1171                              / var_GetFloat( p_instance->p_input, "rate" );
1172         }
1173
1174         TAB_APPEND( i_idsc, pp_idsc, p_idsc );
1175     }
1176     *ppp_idsc = pp_idsc;
1177     *pi_instance = i_idsc;
1178     return VLC_SUCCESS;
1179 }
1180
1181 static int vlm_ControlMediaInstanceClear( vlm_t *p_vlm, int64_t id )
1182 {
1183     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
1184
1185     if( !p_media )
1186         return VLC_EGENERIC;
1187
1188     while( p_media->i_instance > 0 )
1189         vlm_ControlMediaInstanceStop( p_vlm, id, p_media->instance[0]->psz_name );
1190
1191     return VLC_SUCCESS;
1192 }
1193
1194 static int vlm_ControlScheduleClear( vlm_t *p_vlm )
1195 {
1196     while( p_vlm->i_schedule > 0 )
1197         vlm_ScheduleDelete( p_vlm, p_vlm->schedule[0] );
1198
1199     return VLC_SUCCESS;
1200 }
1201
1202 static int vlm_vaControlInternal( vlm_t *p_vlm, int i_query, va_list args )
1203 {
1204     vlm_media_t *p_dsc;
1205     vlm_media_t **pp_dsc;
1206     vlm_media_t ***ppp_dsc;
1207     vlm_media_instance_t ***ppp_idsc;
1208     const char *psz_id;
1209     const char *psz_vod;
1210     int64_t *p_id;
1211     int64_t id;
1212     int i_int;
1213     int *pi_int;
1214
1215     int64_t *pi_i64;
1216     int64_t i_i64;
1217     double *pd_double;
1218     double d_double;
1219
1220     switch( i_query )
1221     {
1222     /* Media control */
1223     case VLM_GET_MEDIAS:
1224         ppp_dsc = (vlm_media_t ***)va_arg( args, vlm_media_t *** );
1225         pi_int = (int *)va_arg( args, int * );
1226         return vlm_ControlMediaGets( p_vlm, ppp_dsc, pi_int );
1227
1228     case VLM_CLEAR_MEDIAS:
1229         return vlm_ControlMediaClear( p_vlm );
1230
1231     case VLM_CHANGE_MEDIA:
1232         p_dsc = (vlm_media_t*)va_arg( args, vlm_media_t * );
1233         return vlm_ControlMediaChange( p_vlm, p_dsc );
1234
1235     case VLM_ADD_MEDIA:
1236         p_dsc = (vlm_media_t*)va_arg( args, vlm_media_t * );
1237         p_id = (int64_t*)va_arg( args, int64_t * );
1238         return vlm_ControlMediaAdd( p_vlm, p_dsc, p_id );
1239
1240     case VLM_DEL_MEDIA:
1241         id = (int64_t)va_arg( args, int64_t );
1242         return vlm_ControlMediaDel( p_vlm, id );
1243
1244     case VLM_GET_MEDIA:
1245         id = (int64_t)va_arg( args, int64_t );
1246         pp_dsc = (vlm_media_t **)va_arg( args, vlm_media_t ** );
1247         return vlm_ControlMediaGet( p_vlm, id, pp_dsc );
1248
1249     case VLM_GET_MEDIA_ID:
1250         psz_id = (const char*)va_arg( args, const char * );
1251         p_id = (int64_t*)va_arg( args, int64_t * );
1252         return vlm_ControlMediaGetId( p_vlm, psz_id, p_id );
1253
1254
1255     /* Media instance control */
1256     case VLM_GET_MEDIA_INSTANCES:
1257         id = (int64_t)va_arg( args, int64_t );
1258         ppp_idsc = (vlm_media_instance_t ***)va_arg( args, vlm_media_instance_t *** );
1259         pi_int = (int *)va_arg( args, int *);
1260         return vlm_ControlMediaInstanceGets( p_vlm, id, ppp_idsc, pi_int );
1261
1262     case VLM_CLEAR_MEDIA_INSTANCES:
1263         id = (int64_t)va_arg( args, int64_t );
1264         return vlm_ControlMediaInstanceClear( p_vlm, id );
1265
1266
1267     case VLM_START_MEDIA_BROADCAST_INSTANCE:
1268         id = (int64_t)va_arg( args, int64_t );
1269         psz_id = (const char*)va_arg( args, const char* );
1270         i_int = (int)va_arg( args, int );
1271         return vlm_ControlMediaInstanceStart( p_vlm, id, psz_id, i_int, NULL );
1272
1273     case VLM_START_MEDIA_VOD_INSTANCE:
1274         id = (int64_t)va_arg( args, int64_t );
1275         psz_id = (const char*)va_arg( args, const char* );
1276         i_int = (int)va_arg( args, int );
1277         psz_vod = (const char*)va_arg( args, const char* );
1278         if( !psz_vod )
1279             return VLC_EGENERIC;
1280         return vlm_ControlMediaInstanceStart( p_vlm, id, psz_id, i_int, psz_vod );
1281
1282     case VLM_STOP_MEDIA_INSTANCE:
1283         id = (int64_t)va_arg( args, int64_t );
1284         psz_id = (const char*)va_arg( args, const char* );
1285         return vlm_ControlMediaInstanceStop( p_vlm, id, psz_id );
1286
1287     case VLM_PAUSE_MEDIA_INSTANCE:
1288         id = (int64_t)va_arg( args, int64_t );
1289         psz_id = (const char*)va_arg( args, const char* );
1290         return vlm_ControlMediaInstancePause( p_vlm, id, psz_id );
1291
1292     case VLM_GET_MEDIA_INSTANCE_TIME:
1293         id = (int64_t)va_arg( args, int64_t );
1294         psz_id = (const char*)va_arg( args, const char* );
1295         pi_i64 = (int64_t*)va_arg( args, int64_t * );
1296         return vlm_ControlMediaInstanceGetTimePosition( p_vlm, id, psz_id, pi_i64, NULL );
1297     case VLM_GET_MEDIA_INSTANCE_POSITION:
1298         id = (int64_t)va_arg( args, int64_t );
1299         psz_id = (const char*)va_arg( args, const char* );
1300         pd_double = (double*)va_arg( args, double* );
1301         return vlm_ControlMediaInstanceGetTimePosition( p_vlm, id, psz_id, NULL, pd_double );
1302
1303     case VLM_SET_MEDIA_INSTANCE_TIME:
1304         id = (int64_t)va_arg( args, int64_t );
1305         psz_id = (const char*)va_arg( args, const char* );
1306         i_i64 = (int64_t)va_arg( args, int64_t);
1307         return vlm_ControlMediaInstanceSetTimePosition( p_vlm, id, psz_id, i_i64, -1 );
1308     case VLM_SET_MEDIA_INSTANCE_POSITION:
1309         id = (int64_t)va_arg( args, int64_t );
1310         psz_id = (const char*)va_arg( args, const char* );
1311         d_double = (double)va_arg( args, double );
1312         return vlm_ControlMediaInstanceSetTimePosition( p_vlm, id, psz_id, -1, d_double );
1313
1314     case VLM_CLEAR_SCHEDULES:
1315         return vlm_ControlScheduleClear( p_vlm );
1316
1317     default:
1318         msg_Err( p_vlm, "unknown VLM query" );
1319         return VLC_EGENERIC;
1320     }
1321 }
1322
1323 int vlm_ControlInternal( vlm_t *p_vlm, int i_query, ... )
1324 {
1325     va_list args;
1326     int     i_result;
1327
1328     va_start( args, i_query );
1329     i_result = vlm_vaControlInternal( p_vlm, i_query, args );
1330     va_end( args );
1331
1332     return i_result;
1333 }
1334
1335 int vlm_Control( vlm_t *p_vlm, int i_query, ... )
1336 {
1337     va_list args;
1338     int     i_result;
1339
1340     va_start( args, i_query );
1341
1342     vlc_mutex_lock( &p_vlm->lock );
1343     i_result = vlm_vaControlInternal( p_vlm, i_query, args );
1344     vlc_mutex_unlock( &p_vlm->lock );
1345
1346     va_end( args );
1347
1348     return i_result;
1349 }
1350