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