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