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