]> git.sesse.net Git - vlc/blob - src/input/vlm.c
Unexport ml_Create() and ml_Destroy()
[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             if( strstr( p_cfg->ppsz_input[0], "://" ) == NULL )
632             {
633                 char *psz_uri = vlc_path2uri( p_cfg->ppsz_input[0], NULL );
634                 p_media->vod.p_item = input_item_New( psz_uri,
635                                                       p_cfg->psz_name );
636                 free( psz_uri );
637             }
638             else
639                 p_media->vod.p_item = input_item_New( p_cfg->ppsz_input[0],
640                                                       p_cfg->psz_name );
641
642             if( p_cfg->psz_output )
643             {
644                 if( asprintf( &psz_output, "%s:description", p_cfg->psz_output )  == -1 )
645                     psz_output = NULL;
646             }
647             else
648                 psz_output = strdup( "#description" );
649
650             if( psz_output && asprintf( &psz_dup, "sout=%s", psz_output ) != -1 )
651             {
652                 input_item_AddOption( p_media->vod.p_item, psz_dup, VLC_INPUT_OPTION_TRUSTED );
653                 free( psz_dup );
654             }
655             free( psz_output );
656
657             for( i = 0; i < p_cfg->i_option; i++ )
658                 input_item_AddOption( p_media->vod.p_item,
659                                       p_cfg->ppsz_option[i], VLC_INPUT_OPTION_TRUSTED );
660
661             if( asprintf( &psz_header, _("Media: %s"), p_cfg->psz_name ) == -1 )
662                 psz_header = NULL;
663
664             sout_description_data_t data;
665             TAB_INIT(data.i_es, data.es);
666
667             p_input = input_Create( p_vlm->p_vod, p_media->vod.p_item, psz_header, NULL );
668             if( p_input )
669             {
670                 vlc_sem_t sem_preparse;
671                 vlc_sem_init( &sem_preparse, 0 );
672
673                 preparse_data_t preparse = { .p_sem = &sem_preparse,
674                                     .b_mux = (p_cfg->vod.psz_mux != NULL) };
675                 var_AddCallback( p_input, "intf-event", InputEventPreparse,
676                                  &preparse );
677
678                 data.sem = &sem_preparse;
679                 var_Create( p_input, "sout-description-data", VLC_VAR_ADDRESS );
680                 var_SetAddress( p_input, "sout-description-data", &data );
681
682                 if( !input_Start( p_input ) )
683                     vlc_sem_wait( &sem_preparse );
684
685                 var_DelCallback( p_input, "intf-event", InputEventPreparse,
686                                  &preparse );
687
688                 input_Stop( p_input, true );
689                 input_Close( p_input );
690                 vlc_sem_destroy( &sem_preparse );
691             }
692             free( psz_header );
693
694             /* XXX: Don't do it that way, but properly use a new input item ref. */
695             input_item_t item = *p_media->vod.p_item;;
696             if( p_cfg->vod.psz_mux )
697             {
698                 const char *psz_mux;
699                 if (!strcmp(p_cfg->vod.psz_mux, "ps"))
700                     psz_mux = "mp2p";
701                 else if (!strcmp(p_cfg->vod.psz_mux, "ts"))
702                     psz_mux = "mp2t";
703                 else
704                     psz_mux = p_cfg->vod.psz_mux;
705
706                 es_format_t es, *p_es = &es;
707                 union {
708                     char text[5];
709                     unsigned char utext[5];
710                     uint32_t value;
711                 } fourcc;
712
713                 sprintf( fourcc.text, "%4.4s", psz_mux );
714                 for( int i = 0; i < 4; i++ )
715                     fourcc.utext[i] = tolower(fourcc.utext[i]);
716
717                 item.i_es = 1;
718                 item.es = &p_es;
719                 es_format_Init( &es, VIDEO_ES, fourcc.value );
720             }
721             else
722             {
723                 item.i_es = data.i_es;
724                 item.es = data.es;
725             }
726             p_media->vod.p_media = p_vlm->p_vod->pf_media_new( p_vlm->p_vod,
727                                                     p_cfg->psz_name, &item );
728
729             TAB_CLEAN(data.i_es, data.es);
730         }
731     }
732     else if ( p_cfg->b_vod )
733         msg_Err( p_vlm, "vod server is not loaded" );
734     else
735     {
736         /* TODO start media if needed */
737     }
738
739     /* TODO add support of var vlm_media_broadcast/vlm_media_vod */
740
741     vlm_SendEventMediaChanged( p_vlm, p_cfg->id, p_cfg->psz_name );
742     return VLC_SUCCESS;
743 }
744 static int vlm_ControlMediaChange( vlm_t *p_vlm, vlm_media_t *p_cfg )
745 {
746     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, p_cfg->id );
747
748     /* */
749     if( !p_media || vlm_MediaDescriptionCheck( p_vlm, p_cfg ) )
750         return VLC_EGENERIC;
751     if( ( p_media->cfg.b_vod && !p_cfg->b_vod ) || ( !p_media->cfg.b_vod && p_cfg->b_vod ) )
752         return VLC_EGENERIC;
753
754     if( 0 )
755     {
756         /* TODO check what are the changes being done (stop instance if needed) */
757     }
758
759     vlm_media_Clean( &p_media->cfg );
760     vlm_media_Copy( &p_media->cfg, p_cfg );
761
762     return vlm_OnMediaUpdate( p_vlm, p_media );
763 }
764
765 static int vlm_ControlMediaAdd( vlm_t *p_vlm, vlm_media_t *p_cfg, int64_t *p_id )
766 {
767     vlm_media_sys_t *p_media;
768
769     if( vlm_MediaDescriptionCheck( p_vlm, p_cfg ) || vlm_ControlMediaGetByName( p_vlm, p_cfg->psz_name ) )
770     {
771         msg_Err( p_vlm, "invalid media description" );
772         return VLC_EGENERIC;
773     }
774     /* Check if we need to load the VOD server */
775     if( p_cfg->b_vod && !p_vlm->p_vod )
776     {
777         p_vlm->p_vod = vlc_custom_create( VLC_OBJECT(p_vlm), sizeof( vod_t ),
778                                           "vod server" );
779         p_vlm->p_vod->p_module = module_need( p_vlm->p_vod, "vod server", "$vod-server", false );
780         if( !p_vlm->p_vod->p_module )
781         {
782             msg_Err( p_vlm, "cannot find vod server" );
783             vlc_object_release( p_vlm->p_vod );
784             p_vlm->p_vod = NULL;
785             return VLC_EGENERIC;
786         }
787
788         p_vlm->p_vod->p_data = p_vlm;
789         p_vlm->p_vod->pf_media_control = vlm_MediaVodControl;
790     }
791
792     p_media = calloc( 1, sizeof( vlm_media_sys_t ) );
793     if( !p_media )
794         return VLC_ENOMEM;
795
796     vlm_media_Copy( &p_media->cfg, p_cfg );
797     p_media->cfg.id = p_vlm->i_id++;
798     /* FIXME do we do something here if enabled is true ? */
799
800     p_media->vod.p_item = input_item_New( NULL, NULL );
801
802     p_media->vod.p_media = NULL;
803     TAB_INIT( p_media->i_instance, p_media->instance );
804
805     /* */
806     TAB_APPEND( p_vlm->i_media, p_vlm->media, p_media );
807
808     if( p_id )
809         *p_id = p_media->cfg.id;
810
811     /* */
812     vlm_SendEventMediaAdded( p_vlm, p_media->cfg.id, p_media->cfg.psz_name );
813     return vlm_OnMediaUpdate( p_vlm, p_media );
814 }
815
816 static int vlm_ControlMediaDel( vlm_t *p_vlm, int64_t id )
817 {
818     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
819
820     if( !p_media )
821         return VLC_EGENERIC;
822
823     while( p_media->i_instance > 0 )
824         vlm_ControlInternal( p_vlm, VLM_STOP_MEDIA_INSTANCE, id, p_media->instance[0]->psz_name );
825
826     if( p_media->cfg.b_vod )
827     {
828         p_media->cfg.b_enabled = false;
829         vlm_OnMediaUpdate( p_vlm, p_media );
830     }
831
832     /* */
833     vlm_SendEventMediaRemoved( p_vlm, id, p_media->cfg.psz_name );
834
835     vlm_media_Clean( &p_media->cfg );
836
837     vlc_gc_decref( p_media->vod.p_item );
838
839     if( p_media->vod.p_media )
840         p_vlm->p_vod->pf_media_del( p_vlm->p_vod, p_media->vod.p_media );
841
842     TAB_REMOVE( p_vlm->i_media, p_vlm->media, p_media );
843     free( p_media );
844
845     return VLC_SUCCESS;
846 }
847
848 static int vlm_ControlMediaGets( vlm_t *p_vlm, vlm_media_t ***ppp_dsc, int *pi_dsc )
849 {
850     vlm_media_t **pp_dsc;
851     int                     i_dsc;
852     int i;
853
854     TAB_INIT( i_dsc, pp_dsc );
855     for( i = 0; i < p_vlm->i_media; i++ )
856     {
857         vlm_media_t *p_dsc = vlm_media_Duplicate( &p_vlm->media[i]->cfg );
858         TAB_APPEND( i_dsc, pp_dsc, p_dsc );
859     }
860
861     *ppp_dsc = pp_dsc;
862     *pi_dsc = i_dsc;
863
864     return VLC_SUCCESS;
865 }
866 static int vlm_ControlMediaClear( vlm_t *p_vlm )
867 {
868     while( p_vlm->i_media > 0 )
869         vlm_ControlMediaDel( p_vlm, p_vlm->media[0]->cfg.id );
870
871     return VLC_SUCCESS;
872 }
873 static int vlm_ControlMediaGet( vlm_t *p_vlm, int64_t id, vlm_media_t **pp_dsc )
874 {
875     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
876     if( !p_media )
877         return VLC_EGENERIC;
878
879     *pp_dsc = vlm_media_Duplicate( &p_media->cfg );
880     return VLC_SUCCESS;
881 }
882 static int vlm_ControlMediaGetId( vlm_t *p_vlm, const char *psz_name, int64_t *p_id )
883 {
884     vlm_media_sys_t *p_media = vlm_ControlMediaGetByName( p_vlm, psz_name );
885     if( !p_media )
886         return VLC_EGENERIC;
887
888     *p_id = p_media->cfg.id;
889     return VLC_SUCCESS;
890 }
891
892 static vlm_media_instance_sys_t *vlm_ControlMediaInstanceGetByName( vlm_media_sys_t *p_media, const char *psz_id )
893 {
894     int i;
895
896     for( i = 0; i < p_media->i_instance; i++ )
897     {
898         const char *psz = p_media->instance[i]->psz_name;
899         if( ( psz == NULL && psz_id == NULL ) ||
900             ( psz && psz_id && !strcmp( psz, psz_id ) ) )
901             return p_media->instance[i];
902     }
903     return NULL;
904 }
905 static vlm_media_instance_sys_t *vlm_MediaInstanceNew( vlm_t *p_vlm, const char *psz_name )
906 {
907     vlm_media_instance_sys_t *p_instance = calloc( 1, sizeof(vlm_media_instance_sys_t) );
908     if( !p_instance )
909         return NULL;
910
911     p_instance->psz_name = NULL;
912     if( psz_name )
913         p_instance->psz_name = strdup( psz_name );
914
915     p_instance->p_item = input_item_New( NULL, NULL );
916
917     p_instance->i_index = 0;
918     p_instance->b_sout_keep = false;
919     p_instance->p_parent = vlc_object_create( p_vlm, sizeof (vlc_object_t) );
920     p_instance->p_input = NULL;
921     p_instance->p_input_resource = NULL;
922
923     return p_instance;
924 }
925 static void vlm_MediaInstanceDelete( vlm_t *p_vlm, int64_t id, vlm_media_instance_sys_t *p_instance, vlm_media_sys_t *p_media )
926 {
927     input_thread_t *p_input = p_instance->p_input;
928     if( p_input )
929     {
930         input_Stop( p_input, true );
931         input_Join( p_input );
932         var_DelCallback( p_instance->p_input, "intf-event", InputEvent, p_media );
933         input_Release( p_input );
934
935         vlm_SendEventMediaInstanceStopped( p_vlm, id, p_media->cfg.psz_name );
936     }
937     if( p_instance->p_input_resource )
938     {
939         input_resource_Terminate( p_instance->p_input_resource );
940         input_resource_Release( p_instance->p_input_resource );
941     }
942     vlc_object_release( p_instance->p_parent );
943
944     TAB_REMOVE( p_media->i_instance, p_media->instance, p_instance );
945     vlc_gc_decref( p_instance->p_item );
946     free( p_instance->psz_name );
947     free( p_instance );
948 }
949
950
951 static int vlm_ControlMediaInstanceStart( vlm_t *p_vlm, int64_t id, const char *psz_id, int i_input_index, const char *psz_vod_output )
952 {
953     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
954     vlm_media_instance_sys_t *p_instance;
955     char *psz_log;
956
957     if( !p_media || !p_media->cfg.b_enabled || p_media->cfg.i_input <= 0 )
958         return VLC_EGENERIC;
959
960     /* TODO support multiple input for VOD with sout-keep ? */
961
962     if( ( p_media->cfg.b_vod && !psz_vod_output ) || ( !p_media->cfg.b_vod && psz_vod_output ) )
963         return VLC_EGENERIC;
964
965     if( i_input_index < 0 || i_input_index >= p_media->cfg.i_input )
966         return VLC_EGENERIC;
967
968     p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
969     if( !p_instance )
970     {
971         vlm_media_t *p_cfg = &p_media->cfg;
972         int i;
973
974         p_instance = vlm_MediaInstanceNew( p_vlm, psz_id );
975         if( !p_instance )
976             return VLC_ENOMEM;
977
978         if ( p_cfg->b_vod )
979         {
980             var_Create( p_instance->p_parent, "vod-media", VLC_VAR_ADDRESS );
981             var_SetAddress( p_instance->p_parent, "vod-media",
982                             p_media->vod.p_media );
983             var_Create( p_instance->p_parent, "vod-session", VLC_VAR_STRING );
984             var_SetString( p_instance->p_parent, "vod-session", psz_id );
985         }
986
987         if( p_cfg->psz_output != NULL || psz_vod_output != NULL )
988         {
989             char *psz_buffer;
990             if( asprintf( &psz_buffer, "sout=%s%s%s",
991                       p_cfg->psz_output ? p_cfg->psz_output : "",
992                       (p_cfg->psz_output && psz_vod_output) ? ":" : psz_vod_output ? "#" : "",
993                       psz_vod_output ? psz_vod_output : "" ) != -1 )
994             {
995                 input_item_AddOption( p_instance->p_item, psz_buffer, VLC_INPUT_OPTION_TRUSTED );
996                 free( psz_buffer );
997             }
998         }
999
1000         for( i = 0; i < p_cfg->i_option; i++ )
1001         {
1002             if( !strcmp( p_cfg->ppsz_option[i], "sout-keep" ) )
1003                 p_instance->b_sout_keep = true;
1004             else if( !strcmp( p_cfg->ppsz_option[i], "nosout-keep" ) || !strcmp( p_cfg->ppsz_option[i], "no-sout-keep" ) )
1005                 p_instance->b_sout_keep = false;
1006             else
1007                 input_item_AddOption( p_instance->p_item, p_cfg->ppsz_option[i], VLC_INPUT_OPTION_TRUSTED );
1008         }
1009         TAB_APPEND( p_media->i_instance, p_media->instance, p_instance );
1010     }
1011
1012     /* Stop old instance */
1013     input_thread_t *p_input = p_instance->p_input;
1014     if( p_input )
1015     {
1016         if( p_instance->i_index == i_input_index &&
1017             !p_input->b_eof && !p_input->b_error )
1018         {
1019             if( var_GetInteger( p_input, "state" ) == PAUSE_S )
1020                 var_SetInteger( p_input, "state",  PLAYING_S );
1021             return VLC_SUCCESS;
1022         }
1023
1024
1025         input_Stop( p_input, true );
1026         input_Join( p_input );
1027         var_DelCallback( p_instance->p_input, "intf-event", InputEvent, p_media );
1028         input_Release( p_input );
1029
1030         if( !p_instance->b_sout_keep )
1031             input_resource_TerminateSout( p_instance->p_input_resource );
1032         input_resource_TerminateVout( p_instance->p_input_resource );
1033
1034         vlm_SendEventMediaInstanceStopped( p_vlm, id, p_media->cfg.psz_name );
1035     }
1036
1037     /* Start new one */
1038     p_instance->i_index = i_input_index;
1039     if( strstr( p_media->cfg.ppsz_input[p_instance->i_index], "://" ) == NULL )
1040     {
1041         char *psz_uri = vlc_path2uri(
1042                           p_media->cfg.ppsz_input[p_instance->i_index], NULL );
1043         input_item_SetURI( p_instance->p_item, psz_uri ) ;
1044         free( psz_uri );
1045     }
1046     else
1047         input_item_SetURI( p_instance->p_item, p_media->cfg.ppsz_input[p_instance->i_index] ) ;
1048
1049     if( asprintf( &psz_log, _("Media: %s"), p_media->cfg.psz_name ) != -1 )
1050     {
1051         if( !p_instance->p_input_resource )
1052             p_instance->p_input_resource = input_resource_New( p_instance->p_parent );
1053
1054         p_instance->p_input = input_Create( p_instance->p_parent,
1055                                             p_instance->p_item, psz_log,
1056                                             p_instance->p_input_resource );
1057         if( p_instance->p_input )
1058         {
1059             var_AddCallback( p_instance->p_input, "intf-event", InputEvent, p_media );
1060
1061             if( input_Start( p_instance->p_input ) != VLC_SUCCESS )
1062             {
1063                 var_DelCallback( p_instance->p_input, "intf-event", InputEvent, p_media );
1064                 vlc_object_release( p_instance->p_input );
1065                 p_instance->p_input = NULL;
1066             }
1067         }
1068
1069         if( !p_instance->p_input )
1070         {
1071             vlm_MediaInstanceDelete( p_vlm, id, p_instance, p_media );
1072         }
1073         else
1074         {
1075             vlm_SendEventMediaInstanceStarted( p_vlm, id, p_media->cfg.psz_name );
1076         }
1077         free( psz_log );
1078     }
1079
1080     return VLC_SUCCESS;
1081 }
1082
1083 static int vlm_ControlMediaInstanceStop( vlm_t *p_vlm, int64_t id, const char *psz_id )
1084 {
1085     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
1086     vlm_media_instance_sys_t *p_instance;
1087
1088     if( !p_media )
1089         return VLC_EGENERIC;
1090
1091     p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
1092     if( !p_instance )
1093         return VLC_EGENERIC;
1094
1095     vlm_MediaInstanceDelete( p_vlm, id, p_instance, p_media );
1096
1097     return VLC_SUCCESS;
1098 }
1099 static int vlm_ControlMediaInstancePause( vlm_t *p_vlm, int64_t id, const char *psz_id )
1100 {
1101     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
1102     vlm_media_instance_sys_t *p_instance;
1103     int i_state;
1104
1105     if( !p_media )
1106         return VLC_EGENERIC;
1107
1108     p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
1109     if( !p_instance || !p_instance->p_input )
1110         return VLC_EGENERIC;
1111
1112     /* Toggle pause state */
1113     i_state = var_GetInteger( p_instance->p_input, "state" );
1114     if( i_state == PAUSE_S && !p_media->cfg.b_vod )
1115         var_SetInteger( p_instance->p_input, "state", PLAYING_S );
1116     else if( i_state == PLAYING_S )
1117         var_SetInteger( p_instance->p_input, "state", PAUSE_S );
1118     return VLC_SUCCESS;
1119 }
1120 static int vlm_ControlMediaInstanceGetTimePosition( vlm_t *p_vlm, int64_t id, const char *psz_id, int64_t *pi_time, double *pd_position )
1121 {
1122     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
1123     vlm_media_instance_sys_t *p_instance;
1124
1125     if( !p_media )
1126         return VLC_EGENERIC;
1127
1128     p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
1129     if( !p_instance || !p_instance->p_input )
1130         return VLC_EGENERIC;
1131
1132     if( pi_time )
1133         *pi_time = var_GetTime( p_instance->p_input, "time" );
1134     if( pd_position )
1135         *pd_position = var_GetFloat( p_instance->p_input, "position" );
1136     return VLC_SUCCESS;
1137 }
1138 static int vlm_ControlMediaInstanceSetTimePosition( vlm_t *p_vlm, int64_t id, const char *psz_id, int64_t i_time, double d_position )
1139 {
1140     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
1141     vlm_media_instance_sys_t *p_instance;
1142
1143     if( !p_media )
1144         return VLC_EGENERIC;
1145
1146     p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
1147     if( !p_instance || !p_instance->p_input )
1148         return VLC_EGENERIC;
1149
1150     if( i_time >= 0 )
1151         return var_SetTime( p_instance->p_input, "time", i_time );
1152     else if( d_position >= 0 && d_position <= 100 )
1153         return var_SetFloat( p_instance->p_input, "position", d_position );
1154     return VLC_EGENERIC;
1155 }
1156
1157 static int vlm_ControlMediaInstanceGets( vlm_t *p_vlm, int64_t id, vlm_media_instance_t ***ppp_idsc, int *pi_instance )
1158 {
1159     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
1160     vlm_media_instance_t **pp_idsc;
1161     int                              i_idsc;
1162     int i;
1163
1164     if( !p_media )
1165         return VLC_EGENERIC;
1166
1167     TAB_INIT( i_idsc, pp_idsc );
1168     for( i = 0; i < p_media->i_instance; i++ )
1169     {
1170         vlm_media_instance_sys_t *p_instance = p_media->instance[i];
1171         vlm_media_instance_t *p_idsc = vlm_media_instance_New();
1172
1173         if( p_instance->psz_name )
1174             p_idsc->psz_name = strdup( p_instance->psz_name );
1175         if( p_instance->p_input )
1176         {
1177             p_idsc->i_time = var_GetTime( p_instance->p_input, "time" );
1178             p_idsc->i_length = var_GetTime( p_instance->p_input, "length" );
1179             p_idsc->d_position = var_GetFloat( p_instance->p_input, "position" );
1180             if( var_GetInteger( p_instance->p_input, "state" ) == PAUSE_S )
1181                 p_idsc->b_paused = true;
1182             p_idsc->i_rate = INPUT_RATE_DEFAULT
1183                              / var_GetFloat( p_instance->p_input, "rate" );
1184         }
1185
1186         TAB_APPEND( i_idsc, pp_idsc, p_idsc );
1187     }
1188     *ppp_idsc = pp_idsc;
1189     *pi_instance = i_idsc;
1190     return VLC_SUCCESS;
1191 }
1192
1193 static int vlm_ControlMediaInstanceClear( vlm_t *p_vlm, int64_t id )
1194 {
1195     vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
1196
1197     if( !p_media )
1198         return VLC_EGENERIC;
1199
1200     while( p_media->i_instance > 0 )
1201         vlm_ControlMediaInstanceStop( p_vlm, id, p_media->instance[0]->psz_name );
1202
1203     return VLC_SUCCESS;
1204 }
1205
1206 static int vlm_ControlScheduleClear( vlm_t *p_vlm )
1207 {
1208     while( p_vlm->i_schedule > 0 )
1209         vlm_ScheduleDelete( p_vlm, p_vlm->schedule[0] );
1210
1211     return VLC_SUCCESS;
1212 }
1213
1214 static int vlm_vaControlInternal( vlm_t *p_vlm, int i_query, va_list args )
1215 {
1216     vlm_media_t *p_dsc;
1217     vlm_media_t **pp_dsc;
1218     vlm_media_t ***ppp_dsc;
1219     vlm_media_instance_t ***ppp_idsc;
1220     const char *psz_id;
1221     const char *psz_vod;
1222     int64_t *p_id;
1223     int64_t id;
1224     int i_int;
1225     int *pi_int;
1226
1227     int64_t *pi_i64;
1228     int64_t i_i64;
1229     double *pd_double;
1230     double d_double;
1231
1232     switch( i_query )
1233     {
1234     /* Media control */
1235     case VLM_GET_MEDIAS:
1236         ppp_dsc = (vlm_media_t ***)va_arg( args, vlm_media_t *** );
1237         pi_int = (int *)va_arg( args, int * );
1238         return vlm_ControlMediaGets( p_vlm, ppp_dsc, pi_int );
1239
1240     case VLM_CLEAR_MEDIAS:
1241         return vlm_ControlMediaClear( p_vlm );
1242
1243     case VLM_CHANGE_MEDIA:
1244         p_dsc = (vlm_media_t*)va_arg( args, vlm_media_t * );
1245         return vlm_ControlMediaChange( p_vlm, p_dsc );
1246
1247     case VLM_ADD_MEDIA:
1248         p_dsc = (vlm_media_t*)va_arg( args, vlm_media_t * );
1249         p_id = (int64_t*)va_arg( args, int64_t * );
1250         return vlm_ControlMediaAdd( p_vlm, p_dsc, p_id );
1251
1252     case VLM_DEL_MEDIA:
1253         id = (int64_t)va_arg( args, int64_t );
1254         return vlm_ControlMediaDel( p_vlm, id );
1255
1256     case VLM_GET_MEDIA:
1257         id = (int64_t)va_arg( args, int64_t );
1258         pp_dsc = (vlm_media_t **)va_arg( args, vlm_media_t ** );
1259         return vlm_ControlMediaGet( p_vlm, id, pp_dsc );
1260
1261     case VLM_GET_MEDIA_ID:
1262         psz_id = (const char*)va_arg( args, const char * );
1263         p_id = (int64_t*)va_arg( args, int64_t * );
1264         return vlm_ControlMediaGetId( p_vlm, psz_id, p_id );
1265
1266
1267     /* Media instance control */
1268     case VLM_GET_MEDIA_INSTANCES:
1269         id = (int64_t)va_arg( args, int64_t );
1270         ppp_idsc = (vlm_media_instance_t ***)va_arg( args, vlm_media_instance_t *** );
1271         pi_int = (int *)va_arg( args, int *);
1272         return vlm_ControlMediaInstanceGets( p_vlm, id, ppp_idsc, pi_int );
1273
1274     case VLM_CLEAR_MEDIA_INSTANCES:
1275         id = (int64_t)va_arg( args, int64_t );
1276         return vlm_ControlMediaInstanceClear( p_vlm, id );
1277
1278
1279     case VLM_START_MEDIA_BROADCAST_INSTANCE:
1280         id = (int64_t)va_arg( args, int64_t );
1281         psz_id = (const char*)va_arg( args, const char* );
1282         i_int = (int)va_arg( args, int );
1283         return vlm_ControlMediaInstanceStart( p_vlm, id, psz_id, i_int, NULL );
1284
1285     case VLM_START_MEDIA_VOD_INSTANCE:
1286         id = (int64_t)va_arg( args, int64_t );
1287         psz_id = (const char*)va_arg( args, const char* );
1288         i_int = (int)va_arg( args, int );
1289         psz_vod = (const char*)va_arg( args, const char* );
1290         if( !psz_vod )
1291             return VLC_EGENERIC;
1292         return vlm_ControlMediaInstanceStart( p_vlm, id, psz_id, i_int, psz_vod );
1293
1294     case VLM_STOP_MEDIA_INSTANCE:
1295         id = (int64_t)va_arg( args, int64_t );
1296         psz_id = (const char*)va_arg( args, const char* );
1297         return vlm_ControlMediaInstanceStop( p_vlm, id, psz_id );
1298
1299     case VLM_PAUSE_MEDIA_INSTANCE:
1300         id = (int64_t)va_arg( args, int64_t );
1301         psz_id = (const char*)va_arg( args, const char* );
1302         return vlm_ControlMediaInstancePause( p_vlm, id, psz_id );
1303
1304     case VLM_GET_MEDIA_INSTANCE_TIME:
1305         id = (int64_t)va_arg( args, int64_t );
1306         psz_id = (const char*)va_arg( args, const char* );
1307         pi_i64 = (int64_t*)va_arg( args, int64_t * );
1308         return vlm_ControlMediaInstanceGetTimePosition( p_vlm, id, psz_id, pi_i64, NULL );
1309     case VLM_GET_MEDIA_INSTANCE_POSITION:
1310         id = (int64_t)va_arg( args, int64_t );
1311         psz_id = (const char*)va_arg( args, const char* );
1312         pd_double = (double*)va_arg( args, double* );
1313         return vlm_ControlMediaInstanceGetTimePosition( p_vlm, id, psz_id, NULL, pd_double );
1314
1315     case VLM_SET_MEDIA_INSTANCE_TIME:
1316         id = (int64_t)va_arg( args, int64_t );
1317         psz_id = (const char*)va_arg( args, const char* );
1318         i_i64 = (int64_t)va_arg( args, int64_t);
1319         return vlm_ControlMediaInstanceSetTimePosition( p_vlm, id, psz_id, i_i64, -1 );
1320     case VLM_SET_MEDIA_INSTANCE_POSITION:
1321         id = (int64_t)va_arg( args, int64_t );
1322         psz_id = (const char*)va_arg( args, const char* );
1323         d_double = (double)va_arg( args, double );
1324         return vlm_ControlMediaInstanceSetTimePosition( p_vlm, id, psz_id, -1, d_double );
1325
1326     case VLM_CLEAR_SCHEDULES:
1327         return vlm_ControlScheduleClear( p_vlm );
1328
1329     default:
1330         msg_Err( p_vlm, "unknown VLM query" );
1331         return VLC_EGENERIC;
1332     }
1333 }
1334
1335 int vlm_ControlInternal( vlm_t *p_vlm, int i_query, ... )
1336 {
1337     va_list args;
1338     int     i_result;
1339
1340     va_start( args, i_query );
1341     i_result = vlm_vaControlInternal( p_vlm, i_query, args );
1342     va_end( args );
1343
1344     return i_result;
1345 }
1346
1347 int vlm_Control( vlm_t *p_vlm, int i_query, ... )
1348 {
1349     va_list args;
1350     int     i_result;
1351
1352     va_start( args, i_query );
1353
1354     vlc_mutex_lock( &p_vlm->lock );
1355     i_result = vlm_vaControlInternal( p_vlm, i_query, args );
1356     vlc_mutex_unlock( &p_vlm->lock );
1357
1358     va_end( args );
1359
1360     return i_result;
1361 }
1362