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