]> git.sesse.net Git - vlc/blob - src/input/vlm.c
VLM: use custom reference count instead of object destructor
[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     static const char vlm_object_name[] = "vlm daemon";
135
136     /* Avoid multiple creation */
137     vlc_mutex_lock( &vlm_mutex );
138
139     p_vlm = *pp_vlm;
140     if( p_vlm )
141     {   /* VLM already exists */
142         if( likely( p_vlm->users < UINT_MAX ) )
143             p_vlm->users++;
144         else
145             p_vlm = NULL;
146         vlc_mutex_unlock( &vlm_mutex );
147         return p_vlm;
148     }
149
150     msg_Dbg( p_this, "creating VLM" );
151
152     p_vlm = vlc_custom_create( p_this->p_libvlc, sizeof( *p_vlm ),
153                                VLC_OBJECT_GENERIC, vlm_object_name );
154     if( !p_vlm )
155     {
156         vlc_mutex_unlock( &vlm_mutex );
157         return NULL;
158     }
159
160     vlc_mutex_init( &p_vlm->lock );
161     vlc_mutex_init( &p_vlm->lock_manage );
162     vlc_cond_init_daytime( &p_vlm->wait_manage );
163     p_vlm->users = 1;
164     p_vlm->input_state_changed = false;
165     p_vlm->i_id = 1;
166     TAB_INIT( p_vlm->i_media, p_vlm->media );
167     TAB_INIT( p_vlm->i_schedule, p_vlm->schedule );
168     p_vlm->p_vod = NULL;
169     var_Create( p_vlm, "intf-event", VLC_VAR_ADDRESS );
170
171     if( vlc_clone( &p_vlm->thread, Manage, p_vlm, VLC_THREAD_PRIORITY_LOW ) )
172     {
173         vlc_cond_destroy( &p_vlm->wait_manage );
174         vlc_mutex_destroy( &p_vlm->lock );
175         vlc_mutex_destroy( &p_vlm->lock_manage );
176         vlc_object_release( p_vlm );
177         vlc_mutex_unlock( &vlm_mutex );
178         return NULL;
179     }
180
181     *pp_vlm = p_vlm; /* for future reference */
182
183     /* Load our configuration file */
184     psz_vlmconf = var_CreateGetString( p_vlm, "vlm-conf" );
185     if( psz_vlmconf && *psz_vlmconf )
186     {
187         vlm_message_t *p_message = NULL;
188         char *psz_buffer = NULL;
189
190         msg_Dbg( p_this, "loading VLM configuration" );
191         if( asprintf(&psz_buffer, "load %s", psz_vlmconf ) != -1 )
192         {
193             msg_Dbg( p_this, "%s", psz_buffer );
194             if( vlm_ExecuteCommand( p_vlm, psz_buffer, &p_message ) )
195                 msg_Warn( p_this, "error while loading the configuration file" );
196
197             vlm_MessageDelete( p_message );
198             free( psz_buffer );
199         }
200     }
201     free( psz_vlmconf );
202
203     vlc_mutex_unlock( &vlm_mutex );
204
205     return p_vlm;
206 }
207
208 /*****************************************************************************
209  * vlm_Delete:
210  *****************************************************************************/
211 void vlm_Delete( vlm_t *p_vlm )
212 {
213     /* vlm_Delete() is serialized against itself, and against vlm_New().
214      * This mutex protects libvlc_priv->p_vlm and p_vlm->users. */
215     vlc_mutex_lock( &vlm_mutex );
216     assert( p_vlm->users > 0 );
217     if( --p_vlm->users == 0 )
218     {
219         assert( libvlc_priv(p_vlm->p_libvlc)->p_vlm = p_vlm );
220         libvlc_priv(p_vlm->p_libvlc)->p_vlm = NULL;
221     }
222     else
223         p_vlm = NULL;
224     vlc_mutex_unlock( &vlm_mutex );
225
226     if( p_vlm == NULL )
227         return;
228
229     /* Destroy and release VLM */
230     vlc_mutex_lock( &p_vlm->lock );
231     vlm_ControlInternal( p_vlm, VLM_CLEAR_MEDIAS );
232     TAB_CLEAN( p_vlm->i_media, p_vlm->media );
233
234     vlm_ControlInternal( p_vlm, VLM_CLEAR_SCHEDULES );
235     TAB_CLEAN( p_vlm->i_schedule, p_vlm->schedule );
236     vlc_mutex_unlock( &p_vlm->lock );
237
238     vlc_object_kill( p_vlm );
239
240     if( p_vlm->p_vod )
241     {
242         module_unneed( p_vlm->p_vod, p_vlm->p_vod->p_module );
243         vlc_object_release( p_vlm->p_vod );
244     }
245
246     vlc_mutex_lock( &p_vlm->lock_manage );
247     p_vlm->input_state_changed = true;
248     vlc_cond_signal( &p_vlm->wait_manage );
249     vlc_mutex_unlock( &p_vlm->lock_manage );
250
251     /*vlc_cancel( p_vlm->thread ); */
252     vlc_join( p_vlm->thread, NULL );
253
254     vlc_cond_destroy( &p_vlm->wait_manage );
255     vlc_mutex_destroy( &p_vlm->lock );
256     vlc_mutex_destroy( &p_vlm->lock_manage );
257     vlc_object_release( p_vlm );
258 }
259
260 /*****************************************************************************
261  * vlm_ExecuteCommand:
262  *****************************************************************************/
263 int vlm_ExecuteCommand( vlm_t *p_vlm, const char *psz_command,
264                         vlm_message_t **pp_message)
265 {
266     int i_result;
267
268     vlc_mutex_lock( &p_vlm->lock );
269     i_result = ExecuteCommand( p_vlm, psz_command, pp_message );
270     vlc_mutex_unlock( &p_vlm->lock );
271
272     return i_result;
273 }
274
275
276 int64_t vlm_Date(void)
277 {
278 #if defined (WIN32) && !defined (UNDER_CE)
279     struct timeb tm;
280     ftime( &tm );
281     return ((int64_t)tm.time) * 1000000 + ((int64_t)tm.millitm) * 1000;
282 #else
283     struct timeval tv_date;
284
285     /* gettimeofday() cannot fail given &tv_date is a valid address */
286     (void)gettimeofday( &tv_date, NULL );
287     return (mtime_t) tv_date.tv_sec * 1000000 + (mtime_t) tv_date.tv_usec;
288 #endif
289 }
290
291
292 /*****************************************************************************
293  *
294  *****************************************************************************/
295 static int vlm_MediaVodControl( void *p_private, vod_media_t *p_vod_media,
296                                 const char *psz_id, int i_query, va_list args )
297 {
298     vlm_t *vlm = (vlm_t *)p_private;
299     int i, i_ret;
300     const char *psz;
301     int64_t id;
302
303     if( !p_private || !p_vod_media )
304         return VLC_EGENERIC;
305
306     vlc_mutex_lock( &vlm->lock );
307
308     /* Find media id */
309     for( i = 0, id = -1; i < vlm->i_media; i++ )
310     {
311         if( p_vod_media == vlm->media[i]->vod.p_media )
312         {
313             id = vlm->media[i]->cfg.id;
314             break;
315         }
316     }
317     if( id == -1 )
318     {
319         vlc_mutex_unlock( &vlm->lock );
320         return VLC_EGENERIC;
321     }
322
323     switch( i_query )
324     {
325     case VOD_MEDIA_PLAY:
326     {
327         psz = (const char *)va_arg( args, const char * );
328         int64_t *i_time = (int64_t *)va_arg( args, int64_t *);
329         bool b_retry = false;
330         if (*i_time < 0)
331         {
332             /* No start time requested: return the current NPT */
333             i_ret = vlm_ControlInternal( vlm, VLM_GET_MEDIA_INSTANCE_TIME, id, psz_id, i_time );
334             /* The instance is not running yet, it will start at 0 */
335             if (i_ret)
336                 *i_time = 0;
337         }
338         else
339         {
340             /* We want to seek before unpausing, but it won't
341              * work if the instance is not running yet. */
342             b_retry = vlm_ControlInternal( vlm, VLM_SET_MEDIA_INSTANCE_TIME, id, psz_id, *i_time );
343         }
344
345         i_ret = vlm_ControlInternal( vlm, VLM_START_MEDIA_VOD_INSTANCE, id, psz_id, 0, psz );
346
347         if (!i_ret && b_retry)
348             i_ret = vlm_ControlInternal( vlm, VLM_SET_MEDIA_INSTANCE_TIME, id, psz_id, *i_time );
349         break;
350     }
351
352     case VOD_MEDIA_PAUSE:
353     {
354         int64_t *i_time = (int64_t *)va_arg( args, int64_t *);
355         i_ret = vlm_ControlInternal( vlm, VLM_PAUSE_MEDIA_INSTANCE, id, psz_id );
356         if (!i_ret)
357             i_ret = vlm_ControlInternal( vlm, VLM_GET_MEDIA_INSTANCE_TIME, id, psz_id, i_time );
358         break;
359     }
360
361     case VOD_MEDIA_STOP:
362         i_ret = vlm_ControlInternal( vlm, VLM_STOP_MEDIA_INSTANCE, id, psz_id );
363         break;
364
365     case VOD_MEDIA_SEEK:
366     {
367         int64_t i_time = (int64_t)va_arg( args, int64_t );
368         i_ret = vlm_ControlInternal( vlm, VLM_SET_MEDIA_INSTANCE_TIME, id, psz_id, i_time );
369         break;
370     }
371
372     case VOD_MEDIA_REWIND:
373     {
374         double d_scale = (double)va_arg( args, double );
375         double d_position;
376
377         vlm_ControlInternal( vlm, VLM_GET_MEDIA_INSTANCE_POSITION, id, psz_id, &d_position );
378         d_position -= (d_scale / 1000.0);
379         if( d_position < 0.0 )
380             d_position = 0.0;
381         i_ret = vlm_ControlInternal( vlm, VLM_SET_MEDIA_INSTANCE_POSITION, id, psz_id, d_position );
382         break;
383     }
384
385     case VOD_MEDIA_FORWARD:
386     {
387         double d_scale = (double)va_arg( args, double );
388         double d_position;
389
390         vlm_ControlInternal( vlm, VLM_GET_MEDIA_INSTANCE_POSITION, id, psz_id, &d_position );
391         d_position += (d_scale / 1000.0);
392         if( d_position > 1.0 )
393             d_position = 1.0;
394         i_ret = vlm_ControlInternal( vlm, VLM_SET_MEDIA_INSTANCE_POSITION, id, psz_id, d_position );
395         break;
396     }
397
398     default:
399         i_ret = VLC_EGENERIC;
400         break;
401     }
402
403     vlc_mutex_unlock( &vlm->lock );
404
405     return i_ret;
406 }
407
408
409 /*****************************************************************************
410  * Manage:
411  *****************************************************************************/
412 static void* Manage( void* p_object )
413 {
414     vlm_t *vlm = (vlm_t*)p_object;
415     int i, j;
416     mtime_t i_lastcheck;
417     mtime_t i_time;
418     mtime_t i_nextschedule = 0;
419
420     int canc = vlc_savecancel ();
421     i_lastcheck = vlm_Date();
422
423     while( !vlm->b_die )
424     {
425         char **ppsz_scheduled_commands = NULL;
426         int    i_scheduled_commands = 0;
427         bool scheduled_command = false;
428
429         vlc_mutex_lock( &vlm->lock_manage );
430         while( !vlm->input_state_changed && !scheduled_command )
431         {
432             if( i_nextschedule )
433                 scheduled_command = vlc_cond_timedwait( &vlm->wait_manage, &vlm->lock_manage, i_nextschedule ) != 0;
434             else
435                 vlc_cond_wait( &vlm->wait_manage, &vlm->lock_manage );
436         }
437         vlm->input_state_changed = false;
438         vlc_mutex_unlock( &vlm->lock_manage );
439         /* destroy the inputs that wants to die, and launch the next input */
440         vlc_mutex_lock( &vlm->lock );
441         for( i = 0; i < vlm->i_media; i++ )
442         {
443             vlm_media_sys_t *p_media = vlm->media[i];
444
445             for( j = 0; j < p_media->i_instance; )
446             {
447                 vlm_media_instance_sys_t *p_instance = p_media->instance[j];
448
449                 if( p_instance->p_input && ( p_instance->p_input->b_eof || p_instance->p_input->b_error ) )
450                 {
451                     int i_new_input_index;
452
453                     /* */
454                     i_new_input_index = p_instance->i_index + 1;
455                     if( !p_media->cfg.b_vod && p_media->cfg.broadcast.b_loop && i_new_input_index >= p_media->cfg.i_input )
456                         i_new_input_index = 0;
457
458                     /* FIXME implement multiple input with VOD */
459                     if( p_media->cfg.b_vod || i_new_input_index >= p_media->cfg.i_input )
460                         vlm_ControlInternal( vlm, VLM_STOP_MEDIA_INSTANCE, p_media->cfg.id, p_instance->psz_name );
461                     else
462                         vlm_ControlInternal( vlm, VLM_START_MEDIA_BROADCAST_INSTANCE, p_media->cfg.id, p_instance->psz_name, i_new_input_index );
463
464                     j = 0;
465                 }
466                 else
467                 {
468                     j++;
469                 }
470             }
471         }
472
473         /* scheduling */
474         i_time = vlm_Date();
475         i_nextschedule = 0;
476
477         for( i = 0; i < vlm->i_schedule; i++ )
478         {
479             mtime_t i_real_date = vlm->schedule[i]->i_date;
480
481             if( vlm->schedule[i]->b_enabled )
482             {
483                 if( vlm->schedule[i]->i_date == 0 ) // now !
484                 {
485                     vlm->schedule[i]->i_date = (i_time / 1000000) * 1000000 ;
486                     i_real_date = i_time;
487                 }
488                 else if( vlm->schedule[i]->i_period != 0 )
489                 {
490                     int j = 0;
491                     while( vlm->schedule[i]->i_date + j *
492                            vlm->schedule[i]->i_period <= i_lastcheck &&
493                            ( vlm->schedule[i]->i_repeat > j ||
494                              vlm->schedule[i]->i_repeat == -1 ) )
495                     {
496                         j++;
497                     }
498
499                     i_real_date = vlm->schedule[i]->i_date + j *
500                         vlm->schedule[i]->i_period;
501                 }
502
503                 if( i_real_date <= i_time )
504                 {
505                     if( i_real_date > i_lastcheck )
506                     {
507                         for( j = 0; j < vlm->schedule[i]->i_command; j++ )
508                         {
509                             TAB_APPEND( i_scheduled_commands,
510                                         ppsz_scheduled_commands,
511                                         strdup(vlm->schedule[i]->command[j] ) );
512                         }
513                     }
514                 }
515                 else if( i_nextschedule == 0 || i_real_date < i_nextschedule )
516                 {
517                     i_nextschedule = i_real_date;
518                 }
519             }
520         }
521
522         while( i_scheduled_commands )
523         {
524             vlm_message_t *message = NULL;
525             char *psz_command = ppsz_scheduled_commands[0];
526             ExecuteCommand( vlm, psz_command,&message );
527
528             /* for now, drop the message */
529             vlm_MessageDelete( message );
530             TAB_REMOVE( i_scheduled_commands,
531                         ppsz_scheduled_commands,
532                         psz_command );
533             free( psz_command );
534         }
535
536         i_lastcheck = i_time;
537         vlc_mutex_unlock( &vlm->lock );
538
539     }
540
541     vlc_restorecancel (canc);
542     return NULL;
543 }
544
545 /* New API
546  */
547 /*
548 typedef struct
549 {
550     struct
551     {
552         int i_connection_count;
553         int i_connection_active;
554     } vod;
555     struct
556     {
557         int        i_count;
558         bool b_playing;
559         int        i_playing_index;
560     } broadcast;
561
562 } vlm_media_status_t;
563 */
564
565 /* */
566 static vlm_media_sys_t *vlm_ControlMediaGetById( vlm_t *p_vlm, int64_t id )
567 {
568     int i;
569
570     for( i = 0; i < p_vlm->i_media; i++ )
571     {
572         if( p_vlm->media[i]->cfg.id == id )
573             return p_vlm->media[i];
574     }
575     return NULL;
576 }
577 static vlm_media_sys_t *vlm_ControlMediaGetByName( vlm_t *p_vlm, const char *psz_name )
578 {
579     int i;
580
581     for( i = 0; i < p_vlm->i_media; i++ )
582     {
583         if( !strcmp( p_vlm->media[i]->cfg.psz_name, psz_name ) )
584             return p_vlm->media[i];
585     }
586     return NULL;
587 }
588 static int vlm_MediaDescriptionCheck( vlm_t *p_vlm, vlm_media_t *p_cfg )
589 {
590     int i;
591
592     if( !p_cfg || !p_cfg->psz_name ||
593         !strcmp( p_cfg->psz_name, "all" ) || !strcmp( p_cfg->psz_name, "media" ) || !strcmp( p_cfg->psz_name, "schedule" ) )
594         return VLC_EGENERIC;
595
596     for( i = 0; i < p_vlm->i_media; i++ )
597     {
598         if( p_vlm->media[i]->cfg.id == p_cfg->id )
599             continue;
600         if( !strcmp( p_vlm->media[i]->cfg.psz_name, p_cfg->psz_name ) )
601             return VLC_EGENERIC;
602     }
603     return VLC_SUCCESS;
604 }
605
606
607 /* Called after a media description is changed/added */
608 static int vlm_OnMediaUpdate( vlm_t *p_vlm, vlm_media_sys_t *p_media )
609 {
610     vlm_media_t *p_cfg = &p_media->cfg;
611     /* Check if we need to create/delete a vod media */
612     if( p_cfg->b_vod && p_vlm->p_vod )
613     {
614         if( !p_cfg->b_enabled && p_media->vod.p_media )
615         {
616             p_vlm->p_vod->pf_media_del( p_vlm->p_vod, p_media->vod.p_media );
617             p_media->vod.p_media = NULL;
618         }
619         else if( p_cfg->b_enabled && !p_media->vod.p_media && p_cfg->i_input )
620         {
621             /* Pre-parse the input */
622             input_thread_t *p_input;
623             char *psz_output;
624             char *psz_header;
625             char *psz_dup;
626             int i;
627
628             vlc_gc_decref( p_media->vod.p_item );
629
630             char *psz_uri = make_URI( p_cfg->ppsz_input[0], NULL );
631             p_media->vod.p_item = input_item_New( p_vlm, psz_uri,
632                 p_cfg->psz_name );
633             free( psz_uri );
634
635             if( p_cfg->psz_output )
636             {
637                 if( asprintf( &psz_output, "%s:description", p_cfg->psz_output )  == -1 )
638                     psz_output = NULL;
639             }
640             else
641                 psz_output = strdup( "#description" );
642
643             if( psz_output && asprintf( &psz_dup, "sout=%s", psz_output ) != -1 )
644             {
645                 input_item_AddOption( p_media->vod.p_item, psz_dup, VLC_INPUT_OPTION_TRUSTED );
646                 free( psz_dup );
647             }
648             free( psz_output );
649
650             for( i = 0; i < p_cfg->i_option; i++ )
651                 input_item_AddOption( p_media->vod.p_item,
652                                       p_cfg->ppsz_option[i], VLC_INPUT_OPTION_TRUSTED );
653
654             if( asprintf( &psz_header, _("Media: %s"), p_cfg->psz_name ) == -1 )
655                 psz_header = NULL;
656
657             sout_description_data_t data;
658             TAB_INIT(data.i_es, data.es);
659
660             p_input = input_Create( p_vlm->p_vod, p_media->vod.p_item, psz_header, NULL );
661             if( p_input )
662             {
663                 vlc_sem_t sem_preparse;
664                 vlc_sem_init( &sem_preparse, 0 );
665
666                 preparse_data_t preparse = { .p_sem = &sem_preparse,
667                                     .b_mux = (p_cfg->vod.psz_mux != NULL) };
668                 var_AddCallback( p_input, "intf-event", InputEventPreparse,
669                                  &preparse );
670
671                 data.sem = &sem_preparse;
672                 var_Create( p_input, "sout-description-data", VLC_VAR_ADDRESS );
673                 var_SetAddress( p_input, "sout-description-data", &data );
674
675                 if( !input_Start( p_input ) )
676                     vlc_sem_wait( &sem_preparse );
677
678                 var_DelCallback( p_input, "intf-event", InputEventPreparse,
679                                  &preparse );
680
681                 input_Stop( p_input, true );
682                 input_Close( p_input );
683                 vlc_sem_destroy( &sem_preparse );
684             }
685             free( psz_header );
686
687             /* XXX: Don't do it that way, but properly use a new input item ref. */
688             input_item_t item = *p_media->vod.p_item;;
689             if( p_cfg->vod.psz_mux )
690             {
691                 const char *psz_mux;
692                 if (!strcmp(p_cfg->vod.psz_mux, "ps"))
693                     psz_mux = "mp2p";
694                 else if (!strcmp(p_cfg->vod.psz_mux, "ts"))
695                     psz_mux = "mp2t";
696                 else
697                     psz_mux = p_cfg->vod.psz_mux;
698
699                 es_format_t es, *p_es = &es;
700                 union { char text[5]; uint32_t value; } fourcc;
701
702                 sprintf( fourcc.text, "%4.4s", psz_mux );
703                 fourcc.text[0] = tolower(fourcc.text[0]);
704                 fourcc.text[1] = tolower(fourcc.text[1]);
705                 fourcc.text[2] = tolower(fourcc.text[2]);
706                 fourcc.text[3] = tolower(fourcc.text[3]);
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                                           VLC_OBJECT_GENERIC, "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( p_vlm, 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( p_vlm, 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