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