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