1 /*****************************************************************************
2 * vlm.c: VLM interface plugin
3 *****************************************************************************
4 * Copyright (C) 2000-2005 VLC authors and VideoLAN
7 * Authors: Simon Latapie <garf@videolan.org>
8 * Laurent Aimar <fenrir@videolan.org>
9 * Gildas Bazin <gbazin@videolan.org>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
33 #include <vlc_common.h>
36 #include <ctype.h> /* tolower() */
40 #include <vlc_modules.h>
43 # include <sys/time.h> /* gettimeofday() */
47 #include <sys/time.h> /* gettimeofday() */
50 #include <time.h> /* ctime() */
51 #if defined (WIN32) && !defined (UNDER_CE)
52 #include <sys/timeb.h> /* ftime() */
56 #include <vlc_input.h>
57 #include <vlc_stream.h>
58 #include "vlm_internal.h"
59 #include "vlm_event.h"
63 #include "../stream_output/stream_output.h"
64 #include "../libvlc.h"
66 /*****************************************************************************
68 *****************************************************************************/
70 static void* Manage( void * );
71 static int vlm_MediaVodControl( void *, vod_media_t
*, const char *, int, va_list );
73 typedef struct preparse_data_t
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
)
82 VLC_UNUSED(p_this
); VLC_UNUSED(psz_cmd
); VLC_UNUSED(oldval
);
83 preparse_data_t
*p_pre
= p_data
;
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
);
92 static int InputEvent( vlc_object_t
*p_this
, char const *psz_cmd
,
93 vlc_value_t oldval
, vlc_value_t newval
,
98 input_thread_t
*p_input
= (input_thread_t
*)p_this
;
99 vlm_t
*p_vlm
= libvlc_priv( p_input
->p_libvlc
)->p_vlm
;
101 vlm_media_sys_t
*p_media
= p_data
;
102 const char *psz_instance_name
= NULL
;
104 if( newval
.i_int
== INPUT_EVENT_STATE
)
106 for( int i
= 0; i
< p_media
->i_instance
; i
++ )
108 if( p_media
->instance
[i
]->p_input
== p_input
)
110 psz_instance_name
= p_media
->instance
[i
]->psz_name
;
114 vlm_SendEventMediaInstanceState( p_vlm
, p_media
->cfg
.id
, p_media
->cfg
.psz_name
, psz_instance_name
, var_GetInteger( p_input
, "state" ) );
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
);
124 static vlc_mutex_t vlm_mutex
= VLC_STATIC_MUTEX
;
127 /*****************************************************************************
129 *****************************************************************************/
130 vlm_t
*vlm_New ( vlc_object_t
*p_this
)
132 vlm_t
*p_vlm
= NULL
, **pp_vlm
= &(libvlc_priv (p_this
->p_libvlc
)->p_vlm
);
135 /* Avoid multiple creation */
136 vlc_mutex_lock( &vlm_mutex
);
140 { /* VLM already exists */
141 if( likely( p_vlm
->users
< UINT_MAX
) )
145 vlc_mutex_unlock( &vlm_mutex
);
149 msg_Dbg( p_this
, "creating VLM" );
151 p_vlm
= vlc_custom_create( p_this
->p_libvlc
, sizeof( *p_vlm
),
155 vlc_mutex_unlock( &vlm_mutex
);
159 vlc_mutex_init( &p_vlm
->lock
);
160 vlc_mutex_init( &p_vlm
->lock_manage
);
161 vlc_cond_init_daytime( &p_vlm
->wait_manage
);
163 p_vlm
->input_state_changed
= false;
165 TAB_INIT( p_vlm
->i_media
, p_vlm
->media
);
166 TAB_INIT( p_vlm
->i_schedule
, p_vlm
->schedule
);
168 var_Create( p_vlm
, "intf-event", VLC_VAR_ADDRESS
);
170 if( vlc_clone( &p_vlm
->thread
, Manage
, p_vlm
, VLC_THREAD_PRIORITY_LOW
) )
172 vlc_cond_destroy( &p_vlm
->wait_manage
);
173 vlc_mutex_destroy( &p_vlm
->lock
);
174 vlc_mutex_destroy( &p_vlm
->lock_manage
);
175 vlc_object_release( p_vlm
);
176 vlc_mutex_unlock( &vlm_mutex
);
180 *pp_vlm
= p_vlm
; /* for future reference */
182 /* Load our configuration file */
183 psz_vlmconf
= var_CreateGetString( p_vlm
, "vlm-conf" );
184 if( psz_vlmconf
&& *psz_vlmconf
)
186 vlm_message_t
*p_message
= NULL
;
187 char *psz_buffer
= NULL
;
189 msg_Dbg( p_this
, "loading VLM configuration" );
190 if( asprintf(&psz_buffer
, "load %s", psz_vlmconf
) != -1 )
192 msg_Dbg( p_this
, "%s", psz_buffer
);
193 if( vlm_ExecuteCommand( p_vlm
, psz_buffer
, &p_message
) )
194 msg_Warn( p_this
, "error while loading the configuration file" );
196 vlm_MessageDelete( p_message
);
202 vlc_mutex_unlock( &vlm_mutex
);
207 /*****************************************************************************
209 *****************************************************************************/
210 void vlm_Delete( vlm_t
*p_vlm
)
212 /* vlm_Delete() is serialized against itself, and against vlm_New().
213 * This mutex protects libvlc_priv->p_vlm and p_vlm->users. */
214 vlc_mutex_lock( &vlm_mutex
);
215 assert( p_vlm
->users
> 0 );
216 if( --p_vlm
->users
== 0 )
218 assert( libvlc_priv(p_vlm
->p_libvlc
)->p_vlm
= p_vlm
);
219 libvlc_priv(p_vlm
->p_libvlc
)->p_vlm
= NULL
;
223 vlc_mutex_unlock( &vlm_mutex
);
228 /* Destroy and release VLM */
229 vlc_mutex_lock( &p_vlm
->lock
);
230 vlm_ControlInternal( p_vlm
, VLM_CLEAR_MEDIAS
);
231 TAB_CLEAN( p_vlm
->i_media
, p_vlm
->media
);
233 vlm_ControlInternal( p_vlm
, VLM_CLEAR_SCHEDULES
);
234 TAB_CLEAN( p_vlm
->i_schedule
, p_vlm
->schedule
);
235 vlc_mutex_unlock( &p_vlm
->lock
);
237 vlc_object_kill( p_vlm
);
241 module_unneed( p_vlm
->p_vod
, p_vlm
->p_vod
->p_module
);
242 vlc_object_release( p_vlm
->p_vod
);
245 vlc_mutex_lock( &p_vlm
->lock_manage
);
246 p_vlm
->input_state_changed
= true;
247 vlc_cond_signal( &p_vlm
->wait_manage
);
248 vlc_mutex_unlock( &p_vlm
->lock_manage
);
250 /*vlc_cancel( p_vlm->thread ); */
251 vlc_join( p_vlm
->thread
, NULL
);
253 vlc_cond_destroy( &p_vlm
->wait_manage
);
254 vlc_mutex_destroy( &p_vlm
->lock
);
255 vlc_mutex_destroy( &p_vlm
->lock_manage
);
256 vlc_object_release( p_vlm
);
259 /*****************************************************************************
260 * vlm_ExecuteCommand:
261 *****************************************************************************/
262 int vlm_ExecuteCommand( vlm_t
*p_vlm
, const char *psz_command
,
263 vlm_message_t
**pp_message
)
267 vlc_mutex_lock( &p_vlm
->lock
);
268 i_result
= ExecuteCommand( p_vlm
, psz_command
, pp_message
);
269 vlc_mutex_unlock( &p_vlm
->lock
);
275 int64_t vlm_Date(void)
277 #if defined (WIN32) && !defined (UNDER_CE)
280 return ((int64_t)tm
.time
) * 1000000 + ((int64_t)tm
.millitm
) * 1000;
282 struct timeval tv_date
;
284 /* gettimeofday() cannot fail given &tv_date is a valid address */
285 (void)gettimeofday( &tv_date
, NULL
);
286 return (mtime_t
) tv_date
.tv_sec
* 1000000 + (mtime_t
) tv_date
.tv_usec
;
291 /*****************************************************************************
293 *****************************************************************************/
294 static int vlm_MediaVodControl( void *p_private
, vod_media_t
*p_vod_media
,
295 const char *psz_id
, int i_query
, va_list args
)
297 vlm_t
*vlm
= (vlm_t
*)p_private
;
302 if( !p_private
|| !p_vod_media
)
305 vlc_mutex_lock( &vlm
->lock
);
308 for( i
= 0, id
= -1; i
< vlm
->i_media
; i
++ )
310 if( p_vod_media
== vlm
->media
[i
]->vod
.p_media
)
312 id
= vlm
->media
[i
]->cfg
.id
;
318 vlc_mutex_unlock( &vlm
->lock
);
326 psz
= (const char *)va_arg( args
, const char * );
327 int64_t *i_time
= (int64_t *)va_arg( args
, int64_t *);
328 bool b_retry
= false;
331 /* No start time requested: return the current NPT */
332 i_ret
= vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_TIME
, id
, psz_id
, i_time
);
333 /* The instance is not running yet, it will start at 0 */
339 /* We want to seek before unpausing, but it won't
340 * work if the instance is not running yet. */
341 b_retry
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_TIME
, id
, psz_id
, *i_time
);
344 i_ret
= vlm_ControlInternal( vlm
, VLM_START_MEDIA_VOD_INSTANCE
, id
, psz_id
, 0, psz
);
346 if (!i_ret
&& b_retry
)
347 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_TIME
, id
, psz_id
, *i_time
);
351 case VOD_MEDIA_PAUSE
:
353 int64_t *i_time
= (int64_t *)va_arg( args
, int64_t *);
354 i_ret
= vlm_ControlInternal( vlm
, VLM_PAUSE_MEDIA_INSTANCE
, id
, psz_id
);
356 i_ret
= vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_TIME
, id
, psz_id
, i_time
);
361 i_ret
= vlm_ControlInternal( vlm
, VLM_STOP_MEDIA_INSTANCE
, id
, psz_id
);
366 int64_t i_time
= (int64_t)va_arg( args
, int64_t );
367 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_TIME
, id
, psz_id
, i_time
);
371 case VOD_MEDIA_REWIND
:
373 double d_scale
= (double)va_arg( args
, double );
376 vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, &d_position
);
377 d_position
-= (d_scale
/ 1000.0);
378 if( d_position
< 0.0 )
380 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, d_position
);
384 case VOD_MEDIA_FORWARD
:
386 double d_scale
= (double)va_arg( args
, double );
389 vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, &d_position
);
390 d_position
+= (d_scale
/ 1000.0);
391 if( d_position
> 1.0 )
393 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, d_position
);
398 i_ret
= VLC_EGENERIC
;
402 vlc_mutex_unlock( &vlm
->lock
);
408 /*****************************************************************************
410 *****************************************************************************/
411 static void* Manage( void* p_object
)
413 vlm_t
*vlm
= (vlm_t
*)p_object
;
417 mtime_t i_nextschedule
= 0;
419 int canc
= vlc_savecancel ();
420 i_lastcheck
= vlm_Date();
424 char **ppsz_scheduled_commands
= NULL
;
425 int i_scheduled_commands
= 0;
426 bool scheduled_command
= false;
428 vlc_mutex_lock( &vlm
->lock_manage
);
429 while( !vlm
->input_state_changed
&& !scheduled_command
)
432 scheduled_command
= vlc_cond_timedwait( &vlm
->wait_manage
, &vlm
->lock_manage
, i_nextschedule
) != 0;
434 vlc_cond_wait( &vlm
->wait_manage
, &vlm
->lock_manage
);
436 vlm
->input_state_changed
= false;
437 vlc_mutex_unlock( &vlm
->lock_manage
);
438 /* destroy the inputs that wants to die, and launch the next input */
439 vlc_mutex_lock( &vlm
->lock
);
440 for( i
= 0; i
< vlm
->i_media
; i
++ )
442 vlm_media_sys_t
*p_media
= vlm
->media
[i
];
444 for( j
= 0; j
< p_media
->i_instance
; )
446 vlm_media_instance_sys_t
*p_instance
= p_media
->instance
[j
];
448 if( p_instance
->p_input
&& ( p_instance
->p_input
->b_eof
|| p_instance
->p_input
->b_error
) )
450 int i_new_input_index
;
453 i_new_input_index
= p_instance
->i_index
+ 1;
454 if( !p_media
->cfg
.b_vod
&& p_media
->cfg
.broadcast
.b_loop
&& i_new_input_index
>= p_media
->cfg
.i_input
)
455 i_new_input_index
= 0;
457 /* FIXME implement multiple input with VOD */
458 if( p_media
->cfg
.b_vod
|| i_new_input_index
>= p_media
->cfg
.i_input
)
459 vlm_ControlInternal( vlm
, VLM_STOP_MEDIA_INSTANCE
, p_media
->cfg
.id
, p_instance
->psz_name
);
461 vlm_ControlInternal( vlm
, VLM_START_MEDIA_BROADCAST_INSTANCE
, p_media
->cfg
.id
, p_instance
->psz_name
, i_new_input_index
);
476 for( i
= 0; i
< vlm
->i_schedule
; i
++ )
478 mtime_t i_real_date
= vlm
->schedule
[i
]->i_date
;
480 if( vlm
->schedule
[i
]->b_enabled
)
482 if( vlm
->schedule
[i
]->i_date
== 0 ) // now !
484 vlm
->schedule
[i
]->i_date
= (i_time
/ 1000000) * 1000000 ;
485 i_real_date
= i_time
;
487 else if( vlm
->schedule
[i
]->i_period
!= 0 )
490 while( vlm
->schedule
[i
]->i_date
+ j
*
491 vlm
->schedule
[i
]->i_period
<= i_lastcheck
&&
492 ( vlm
->schedule
[i
]->i_repeat
> j
||
493 vlm
->schedule
[i
]->i_repeat
== -1 ) )
498 i_real_date
= vlm
->schedule
[i
]->i_date
+ j
*
499 vlm
->schedule
[i
]->i_period
;
502 if( i_real_date
<= i_time
)
504 if( i_real_date
> i_lastcheck
)
506 for( j
= 0; j
< vlm
->schedule
[i
]->i_command
; j
++ )
508 TAB_APPEND( i_scheduled_commands
,
509 ppsz_scheduled_commands
,
510 strdup(vlm
->schedule
[i
]->command
[j
] ) );
514 else if( i_nextschedule
== 0 || i_real_date
< i_nextschedule
)
516 i_nextschedule
= i_real_date
;
521 while( i_scheduled_commands
)
523 vlm_message_t
*message
= NULL
;
524 char *psz_command
= ppsz_scheduled_commands
[0];
525 ExecuteCommand( vlm
, psz_command
,&message
);
527 /* for now, drop the message */
528 vlm_MessageDelete( message
);
529 TAB_REMOVE( i_scheduled_commands
,
530 ppsz_scheduled_commands
,
535 i_lastcheck
= i_time
;
536 vlc_mutex_unlock( &vlm
->lock
);
540 vlc_restorecancel (canc
);
551 int i_connection_count;
552 int i_connection_active;
561 } vlm_media_status_t;
565 static vlm_media_sys_t
*vlm_ControlMediaGetById( vlm_t
*p_vlm
, int64_t id
)
569 for( i
= 0; i
< p_vlm
->i_media
; i
++ )
571 if( p_vlm
->media
[i
]->cfg
.id
== id
)
572 return p_vlm
->media
[i
];
576 static vlm_media_sys_t
*vlm_ControlMediaGetByName( vlm_t
*p_vlm
, const char *psz_name
)
580 for( i
= 0; i
< p_vlm
->i_media
; i
++ )
582 if( !strcmp( p_vlm
->media
[i
]->cfg
.psz_name
, psz_name
) )
583 return p_vlm
->media
[i
];
587 static int vlm_MediaDescriptionCheck( vlm_t
*p_vlm
, vlm_media_t
*p_cfg
)
591 if( !p_cfg
|| !p_cfg
->psz_name
||
592 !strcmp( p_cfg
->psz_name
, "all" ) || !strcmp( p_cfg
->psz_name
, "media" ) || !strcmp( p_cfg
->psz_name
, "schedule" ) )
595 for( i
= 0; i
< p_vlm
->i_media
; i
++ )
597 if( p_vlm
->media
[i
]->cfg
.id
== p_cfg
->id
)
599 if( !strcmp( p_vlm
->media
[i
]->cfg
.psz_name
, p_cfg
->psz_name
) )
606 /* Called after a media description is changed/added */
607 static int vlm_OnMediaUpdate( vlm_t
*p_vlm
, vlm_media_sys_t
*p_media
)
609 vlm_media_t
*p_cfg
= &p_media
->cfg
;
610 /* Check if we need to create/delete a vod media */
611 if( p_cfg
->b_vod
&& p_vlm
->p_vod
)
613 if( !p_cfg
->b_enabled
&& p_media
->vod
.p_media
)
615 p_vlm
->p_vod
->pf_media_del( p_vlm
->p_vod
, p_media
->vod
.p_media
);
616 p_media
->vod
.p_media
= NULL
;
618 else if( p_cfg
->b_enabled
&& !p_media
->vod
.p_media
&& p_cfg
->i_input
)
620 /* Pre-parse the input */
621 input_thread_t
*p_input
;
627 vlc_gc_decref( p_media
->vod
.p_item
);
629 char *psz_uri
= make_URI( p_cfg
->ppsz_input
[0], NULL
);
630 p_media
->vod
.p_item
= input_item_New( psz_uri
, p_cfg
->psz_name
);
633 if( p_cfg
->psz_output
)
635 if( asprintf( &psz_output
, "%s:description", p_cfg
->psz_output
) == -1 )
639 psz_output
= strdup( "#description" );
641 if( psz_output
&& asprintf( &psz_dup
, "sout=%s", psz_output
) != -1 )
643 input_item_AddOption( p_media
->vod
.p_item
, psz_dup
, VLC_INPUT_OPTION_TRUSTED
);
648 for( i
= 0; i
< p_cfg
->i_option
; i
++ )
649 input_item_AddOption( p_media
->vod
.p_item
,
650 p_cfg
->ppsz_option
[i
], VLC_INPUT_OPTION_TRUSTED
);
652 if( asprintf( &psz_header
, _("Media: %s"), p_cfg
->psz_name
) == -1 )
655 sout_description_data_t data
;
656 TAB_INIT(data
.i_es
, data
.es
);
658 p_input
= input_Create( p_vlm
->p_vod
, p_media
->vod
.p_item
, psz_header
, NULL
);
661 vlc_sem_t sem_preparse
;
662 vlc_sem_init( &sem_preparse
, 0 );
664 preparse_data_t preparse
= { .p_sem
= &sem_preparse
,
665 .b_mux
= (p_cfg
->vod
.psz_mux
!= NULL
) };
666 var_AddCallback( p_input
, "intf-event", InputEventPreparse
,
669 data
.sem
= &sem_preparse
;
670 var_Create( p_input
, "sout-description-data", VLC_VAR_ADDRESS
);
671 var_SetAddress( p_input
, "sout-description-data", &data
);
673 if( !input_Start( p_input
) )
674 vlc_sem_wait( &sem_preparse
);
676 var_DelCallback( p_input
, "intf-event", InputEventPreparse
,
679 input_Stop( p_input
, true );
680 input_Close( p_input
);
681 vlc_sem_destroy( &sem_preparse
);
685 /* XXX: Don't do it that way, but properly use a new input item ref. */
686 input_item_t item
= *p_media
->vod
.p_item
;;
687 if( p_cfg
->vod
.psz_mux
)
690 if (!strcmp(p_cfg
->vod
.psz_mux
, "ps"))
692 else if (!strcmp(p_cfg
->vod
.psz_mux
, "ts"))
695 psz_mux
= p_cfg
->vod
.psz_mux
;
697 es_format_t es
, *p_es
= &es
;
700 unsigned char utext
[5];
704 sprintf( fourcc
.text
, "%4.4s", psz_mux
);
705 for( int i
= 0; i
< 4; i
++ )
706 fourcc
.utext
[i
] = tolower(fourcc
.utext
[i
]);
710 es_format_Init( &es
, VIDEO_ES
, fourcc
.value
);
714 item
.i_es
= data
.i_es
;
717 p_media
->vod
.p_media
= p_vlm
->p_vod
->pf_media_new( p_vlm
->p_vod
,
718 p_cfg
->psz_name
, &item
);
720 TAB_CLEAN(data
.i_es
, data
.es
);
723 else if ( p_cfg
->b_vod
)
724 msg_Err( p_vlm
, "vod server is not loaded" );
727 /* TODO start media if needed */
730 /* TODO add support of var vlm_media_broadcast/vlm_media_vod */
732 vlm_SendEventMediaChanged( p_vlm
, p_cfg
->id
, p_cfg
->psz_name
);
735 static int vlm_ControlMediaChange( vlm_t
*p_vlm
, vlm_media_t
*p_cfg
)
737 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, p_cfg
->id
);
740 if( !p_media
|| vlm_MediaDescriptionCheck( p_vlm
, p_cfg
) )
742 if( ( p_media
->cfg
.b_vod
&& !p_cfg
->b_vod
) || ( !p_media
->cfg
.b_vod
&& p_cfg
->b_vod
) )
747 /* TODO check what are the changes being done (stop instance if needed) */
750 vlm_media_Clean( &p_media
->cfg
);
751 vlm_media_Copy( &p_media
->cfg
, p_cfg
);
753 return vlm_OnMediaUpdate( p_vlm
, p_media
);
756 static int vlm_ControlMediaAdd( vlm_t
*p_vlm
, vlm_media_t
*p_cfg
, int64_t *p_id
)
758 vlm_media_sys_t
*p_media
;
760 if( vlm_MediaDescriptionCheck( p_vlm
, p_cfg
) || vlm_ControlMediaGetByName( p_vlm
, p_cfg
->psz_name
) )
762 msg_Err( p_vlm
, "invalid media description" );
765 /* Check if we need to load the VOD server */
766 if( p_cfg
->b_vod
&& !p_vlm
->p_vod
)
768 p_vlm
->p_vod
= vlc_custom_create( VLC_OBJECT(p_vlm
), sizeof( vod_t
),
770 p_vlm
->p_vod
->p_module
= module_need( p_vlm
->p_vod
, "vod server", "$vod-server", false );
771 if( !p_vlm
->p_vod
->p_module
)
773 msg_Err( p_vlm
, "cannot find vod server" );
774 vlc_object_release( p_vlm
->p_vod
);
779 p_vlm
->p_vod
->p_data
= p_vlm
;
780 p_vlm
->p_vod
->pf_media_control
= vlm_MediaVodControl
;
783 p_media
= calloc( 1, sizeof( vlm_media_sys_t
) );
787 vlm_media_Copy( &p_media
->cfg
, p_cfg
);
788 p_media
->cfg
.id
= p_vlm
->i_id
++;
789 /* FIXME do we do something here if enabled is true ? */
791 p_media
->vod
.p_item
= input_item_New( NULL
, NULL
);
793 p_media
->vod
.p_media
= NULL
;
794 TAB_INIT( p_media
->i_instance
, p_media
->instance
);
797 TAB_APPEND( p_vlm
->i_media
, p_vlm
->media
, p_media
);
800 *p_id
= p_media
->cfg
.id
;
803 vlm_SendEventMediaAdded( p_vlm
, p_media
->cfg
.id
, p_media
->cfg
.psz_name
);
804 return vlm_OnMediaUpdate( p_vlm
, p_media
);
807 static int vlm_ControlMediaDel( vlm_t
*p_vlm
, int64_t id
)
809 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
814 while( p_media
->i_instance
> 0 )
815 vlm_ControlInternal( p_vlm
, VLM_STOP_MEDIA_INSTANCE
, id
, p_media
->instance
[0]->psz_name
);
817 if( p_media
->cfg
.b_vod
)
819 p_media
->cfg
.b_enabled
= false;
820 vlm_OnMediaUpdate( p_vlm
, p_media
);
824 vlm_SendEventMediaRemoved( p_vlm
, id
, p_media
->cfg
.psz_name
);
826 vlm_media_Clean( &p_media
->cfg
);
828 vlc_gc_decref( p_media
->vod
.p_item
);
830 if( p_media
->vod
.p_media
)
831 p_vlm
->p_vod
->pf_media_del( p_vlm
->p_vod
, p_media
->vod
.p_media
);
833 TAB_REMOVE( p_vlm
->i_media
, p_vlm
->media
, p_media
);
839 static int vlm_ControlMediaGets( vlm_t
*p_vlm
, vlm_media_t
***ppp_dsc
, int *pi_dsc
)
841 vlm_media_t
**pp_dsc
;
845 TAB_INIT( i_dsc
, pp_dsc
);
846 for( i
= 0; i
< p_vlm
->i_media
; i
++ )
848 vlm_media_t
*p_dsc
= vlm_media_Duplicate( &p_vlm
->media
[i
]->cfg
);
849 TAB_APPEND( i_dsc
, pp_dsc
, p_dsc
);
857 static int vlm_ControlMediaClear( vlm_t
*p_vlm
)
859 while( p_vlm
->i_media
> 0 )
860 vlm_ControlMediaDel( p_vlm
, p_vlm
->media
[0]->cfg
.id
);
864 static int vlm_ControlMediaGet( vlm_t
*p_vlm
, int64_t id
, vlm_media_t
**pp_dsc
)
866 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
870 *pp_dsc
= vlm_media_Duplicate( &p_media
->cfg
);
873 static int vlm_ControlMediaGetId( vlm_t
*p_vlm
, const char *psz_name
, int64_t *p_id
)
875 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetByName( p_vlm
, psz_name
);
879 *p_id
= p_media
->cfg
.id
;
883 static vlm_media_instance_sys_t
*vlm_ControlMediaInstanceGetByName( vlm_media_sys_t
*p_media
, const char *psz_id
)
887 for( i
= 0; i
< p_media
->i_instance
; i
++ )
889 const char *psz
= p_media
->instance
[i
]->psz_name
;
890 if( ( psz
== NULL
&& psz_id
== NULL
) ||
891 ( psz
&& psz_id
&& !strcmp( psz
, psz_id
) ) )
892 return p_media
->instance
[i
];
896 static vlm_media_instance_sys_t
*vlm_MediaInstanceNew( vlm_t
*p_vlm
, const char *psz_name
)
898 vlm_media_instance_sys_t
*p_instance
= calloc( 1, sizeof(vlm_media_instance_sys_t
) );
902 p_instance
->psz_name
= NULL
;
904 p_instance
->psz_name
= strdup( psz_name
);
906 p_instance
->p_item
= input_item_New( NULL
, NULL
);
908 p_instance
->i_index
= 0;
909 p_instance
->b_sout_keep
= false;
910 p_instance
->p_parent
= vlc_object_create( p_vlm
, sizeof (vlc_object_t
) );
911 p_instance
->p_input
= NULL
;
912 p_instance
->p_input_resource
= NULL
;
916 static void vlm_MediaInstanceDelete( vlm_t
*p_vlm
, int64_t id
, vlm_media_instance_sys_t
*p_instance
, vlm_media_sys_t
*p_media
)
918 input_thread_t
*p_input
= p_instance
->p_input
;
921 input_Stop( p_input
, true );
922 input_Join( p_input
);
923 var_DelCallback( p_instance
->p_input
, "intf-event", InputEvent
, p_media
);
924 input_Release( p_input
);
926 vlm_SendEventMediaInstanceStopped( p_vlm
, id
, p_media
->cfg
.psz_name
);
928 if( p_instance
->p_input_resource
)
930 input_resource_Terminate( p_instance
->p_input_resource
);
931 input_resource_Release( p_instance
->p_input_resource
);
933 vlc_object_release( p_instance
->p_parent
);
935 TAB_REMOVE( p_media
->i_instance
, p_media
->instance
, p_instance
);
936 vlc_gc_decref( p_instance
->p_item
);
937 free( p_instance
->psz_name
);
942 static int vlm_ControlMediaInstanceStart( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
, int i_input_index
, const char *psz_vod_output
)
944 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
945 vlm_media_instance_sys_t
*p_instance
;
948 if( !p_media
|| !p_media
->cfg
.b_enabled
|| p_media
->cfg
.i_input
<= 0 )
951 /* TODO support multiple input for VOD with sout-keep ? */
953 if( ( p_media
->cfg
.b_vod
&& !psz_vod_output
) || ( !p_media
->cfg
.b_vod
&& psz_vod_output
) )
956 if( i_input_index
< 0 || i_input_index
>= p_media
->cfg
.i_input
)
959 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
962 vlm_media_t
*p_cfg
= &p_media
->cfg
;
965 p_instance
= vlm_MediaInstanceNew( p_vlm
, psz_id
);
971 var_Create( p_instance
->p_parent
, "vod-media", VLC_VAR_ADDRESS
);
972 var_SetAddress( p_instance
->p_parent
, "vod-media",
973 p_media
->vod
.p_media
);
974 var_Create( p_instance
->p_parent
, "vod-session", VLC_VAR_STRING
);
975 var_SetString( p_instance
->p_parent
, "vod-session", psz_id
);
978 if( p_cfg
->psz_output
!= NULL
|| psz_vod_output
!= NULL
)
981 if( asprintf( &psz_buffer
, "sout=%s%s%s",
982 p_cfg
->psz_output
? p_cfg
->psz_output
: "",
983 (p_cfg
->psz_output
&& psz_vod_output
) ? ":" : psz_vod_output
? "#" : "",
984 psz_vod_output
? psz_vod_output
: "" ) != -1 )
986 input_item_AddOption( p_instance
->p_item
, psz_buffer
, VLC_INPUT_OPTION_TRUSTED
);
991 for( i
= 0; i
< p_cfg
->i_option
; i
++ )
993 if( !strcmp( p_cfg
->ppsz_option
[i
], "sout-keep" ) )
994 p_instance
->b_sout_keep
= true;
995 else if( !strcmp( p_cfg
->ppsz_option
[i
], "nosout-keep" ) || !strcmp( p_cfg
->ppsz_option
[i
], "no-sout-keep" ) )
996 p_instance
->b_sout_keep
= false;
998 input_item_AddOption( p_instance
->p_item
, p_cfg
->ppsz_option
[i
], VLC_INPUT_OPTION_TRUSTED
);
1000 TAB_APPEND( p_media
->i_instance
, p_media
->instance
, p_instance
);
1003 /* Stop old instance */
1004 input_thread_t
*p_input
= p_instance
->p_input
;
1007 if( p_instance
->i_index
== i_input_index
&&
1008 !p_input
->b_eof
&& !p_input
->b_error
)
1010 if( var_GetInteger( p_input
, "state" ) == PAUSE_S
)
1011 var_SetInteger( p_input
, "state", PLAYING_S
);
1016 input_Stop( p_input
, true );
1017 input_Join( p_input
);
1018 var_DelCallback( p_instance
->p_input
, "intf-event", InputEvent
, p_media
);
1019 input_Release( p_input
);
1021 if( !p_instance
->b_sout_keep
)
1022 input_resource_TerminateSout( p_instance
->p_input_resource
);
1023 input_resource_TerminateVout( p_instance
->p_input_resource
);
1025 vlm_SendEventMediaInstanceStopped( p_vlm
, id
, p_media
->cfg
.psz_name
);
1029 p_instance
->i_index
= i_input_index
;
1030 char *psz_uri
= make_URI( p_media
->cfg
.ppsz_input
[p_instance
->i_index
],
1032 input_item_SetURI( p_instance
->p_item
, psz_uri
) ;
1035 if( asprintf( &psz_log
, _("Media: %s"), p_media
->cfg
.psz_name
) != -1 )
1037 if( !p_instance
->p_input_resource
)
1038 p_instance
->p_input_resource
= input_resource_New( p_instance
->p_parent
);
1040 p_instance
->p_input
= input_Create( p_instance
->p_parent
,
1041 p_instance
->p_item
, psz_log
,
1042 p_instance
->p_input_resource
);
1043 if( p_instance
->p_input
)
1045 var_AddCallback( p_instance
->p_input
, "intf-event", InputEvent
, p_media
);
1047 if( input_Start( p_instance
->p_input
) != VLC_SUCCESS
)
1049 var_DelCallback( p_instance
->p_input
, "intf-event", InputEvent
, p_media
);
1050 vlc_object_release( p_instance
->p_input
);
1051 p_instance
->p_input
= NULL
;
1055 if( !p_instance
->p_input
)
1057 vlm_MediaInstanceDelete( p_vlm
, id
, p_instance
, p_media
);
1061 vlm_SendEventMediaInstanceStarted( p_vlm
, id
, p_media
->cfg
.psz_name
);
1069 static int vlm_ControlMediaInstanceStop( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
)
1071 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1072 vlm_media_instance_sys_t
*p_instance
;
1075 return VLC_EGENERIC
;
1077 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
1079 return VLC_EGENERIC
;
1081 vlm_MediaInstanceDelete( p_vlm
, id
, p_instance
, p_media
);
1085 static int vlm_ControlMediaInstancePause( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
)
1087 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1088 vlm_media_instance_sys_t
*p_instance
;
1092 return VLC_EGENERIC
;
1094 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
1095 if( !p_instance
|| !p_instance
->p_input
)
1096 return VLC_EGENERIC
;
1098 /* Toggle pause state */
1099 i_state
= var_GetInteger( p_instance
->p_input
, "state" );
1100 if( i_state
== PAUSE_S
&& !p_media
->cfg
.b_vod
)
1101 var_SetInteger( p_instance
->p_input
, "state", PLAYING_S
);
1102 else if( i_state
== PLAYING_S
)
1103 var_SetInteger( p_instance
->p_input
, "state", PAUSE_S
);
1106 static int vlm_ControlMediaInstanceGetTimePosition( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
, int64_t *pi_time
, double *pd_position
)
1108 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1109 vlm_media_instance_sys_t
*p_instance
;
1112 return VLC_EGENERIC
;
1114 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
1115 if( !p_instance
|| !p_instance
->p_input
)
1116 return VLC_EGENERIC
;
1119 *pi_time
= var_GetTime( p_instance
->p_input
, "time" );
1121 *pd_position
= var_GetFloat( p_instance
->p_input
, "position" );
1124 static int vlm_ControlMediaInstanceSetTimePosition( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
, int64_t i_time
, double d_position
)
1126 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1127 vlm_media_instance_sys_t
*p_instance
;
1130 return VLC_EGENERIC
;
1132 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
1133 if( !p_instance
|| !p_instance
->p_input
)
1134 return VLC_EGENERIC
;
1137 return var_SetTime( p_instance
->p_input
, "time", i_time
);
1138 else if( d_position
>= 0 && d_position
<= 100 )
1139 return var_SetFloat( p_instance
->p_input
, "position", d_position
);
1140 return VLC_EGENERIC
;
1143 static int vlm_ControlMediaInstanceGets( vlm_t
*p_vlm
, int64_t id
, vlm_media_instance_t
***ppp_idsc
, int *pi_instance
)
1145 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1146 vlm_media_instance_t
**pp_idsc
;
1151 return VLC_EGENERIC
;
1153 TAB_INIT( i_idsc
, pp_idsc
);
1154 for( i
= 0; i
< p_media
->i_instance
; i
++ )
1156 vlm_media_instance_sys_t
*p_instance
= p_media
->instance
[i
];
1157 vlm_media_instance_t
*p_idsc
= vlm_media_instance_New();
1159 if( p_instance
->psz_name
)
1160 p_idsc
->psz_name
= strdup( p_instance
->psz_name
);
1161 if( p_instance
->p_input
)
1163 p_idsc
->i_time
= var_GetTime( p_instance
->p_input
, "time" );
1164 p_idsc
->i_length
= var_GetTime( p_instance
->p_input
, "length" );
1165 p_idsc
->d_position
= var_GetFloat( p_instance
->p_input
, "position" );
1166 if( var_GetInteger( p_instance
->p_input
, "state" ) == PAUSE_S
)
1167 p_idsc
->b_paused
= true;
1168 p_idsc
->i_rate
= INPUT_RATE_DEFAULT
1169 / var_GetFloat( p_instance
->p_input
, "rate" );
1172 TAB_APPEND( i_idsc
, pp_idsc
, p_idsc
);
1174 *ppp_idsc
= pp_idsc
;
1175 *pi_instance
= i_idsc
;
1179 static int vlm_ControlMediaInstanceClear( vlm_t
*p_vlm
, int64_t id
)
1181 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1184 return VLC_EGENERIC
;
1186 while( p_media
->i_instance
> 0 )
1187 vlm_ControlMediaInstanceStop( p_vlm
, id
, p_media
->instance
[0]->psz_name
);
1192 static int vlm_ControlScheduleClear( vlm_t
*p_vlm
)
1194 while( p_vlm
->i_schedule
> 0 )
1195 vlm_ScheduleDelete( p_vlm
, p_vlm
->schedule
[0] );
1200 static int vlm_vaControlInternal( vlm_t
*p_vlm
, int i_query
, va_list args
)
1203 vlm_media_t
**pp_dsc
;
1204 vlm_media_t
***ppp_dsc
;
1205 vlm_media_instance_t
***ppp_idsc
;
1207 const char *psz_vod
;
1221 case VLM_GET_MEDIAS
:
1222 ppp_dsc
= (vlm_media_t
***)va_arg( args
, vlm_media_t
*** );
1223 pi_int
= (int *)va_arg( args
, int * );
1224 return vlm_ControlMediaGets( p_vlm
, ppp_dsc
, pi_int
);
1226 case VLM_CLEAR_MEDIAS
:
1227 return vlm_ControlMediaClear( p_vlm
);
1229 case VLM_CHANGE_MEDIA
:
1230 p_dsc
= (vlm_media_t
*)va_arg( args
, vlm_media_t
* );
1231 return vlm_ControlMediaChange( p_vlm
, p_dsc
);
1234 p_dsc
= (vlm_media_t
*)va_arg( args
, vlm_media_t
* );
1235 p_id
= (int64_t*)va_arg( args
, int64_t * );
1236 return vlm_ControlMediaAdd( p_vlm
, p_dsc
, p_id
);
1239 id
= (int64_t)va_arg( args
, int64_t );
1240 return vlm_ControlMediaDel( p_vlm
, id
);
1243 id
= (int64_t)va_arg( args
, int64_t );
1244 pp_dsc
= (vlm_media_t
**)va_arg( args
, vlm_media_t
** );
1245 return vlm_ControlMediaGet( p_vlm
, id
, pp_dsc
);
1247 case VLM_GET_MEDIA_ID
:
1248 psz_id
= (const char*)va_arg( args
, const char * );
1249 p_id
= (int64_t*)va_arg( args
, int64_t * );
1250 return vlm_ControlMediaGetId( p_vlm
, psz_id
, p_id
);
1253 /* Media instance control */
1254 case VLM_GET_MEDIA_INSTANCES
:
1255 id
= (int64_t)va_arg( args
, int64_t );
1256 ppp_idsc
= (vlm_media_instance_t
***)va_arg( args
, vlm_media_instance_t
*** );
1257 pi_int
= (int *)va_arg( args
, int *);
1258 return vlm_ControlMediaInstanceGets( p_vlm
, id
, ppp_idsc
, pi_int
);
1260 case VLM_CLEAR_MEDIA_INSTANCES
:
1261 id
= (int64_t)va_arg( args
, int64_t );
1262 return vlm_ControlMediaInstanceClear( p_vlm
, id
);
1265 case VLM_START_MEDIA_BROADCAST_INSTANCE
:
1266 id
= (int64_t)va_arg( args
, int64_t );
1267 psz_id
= (const char*)va_arg( args
, const char* );
1268 i_int
= (int)va_arg( args
, int );
1269 return vlm_ControlMediaInstanceStart( p_vlm
, id
, psz_id
, i_int
, NULL
);
1271 case VLM_START_MEDIA_VOD_INSTANCE
:
1272 id
= (int64_t)va_arg( args
, int64_t );
1273 psz_id
= (const char*)va_arg( args
, const char* );
1274 i_int
= (int)va_arg( args
, int );
1275 psz_vod
= (const char*)va_arg( args
, const char* );
1277 return VLC_EGENERIC
;
1278 return vlm_ControlMediaInstanceStart( p_vlm
, id
, psz_id
, i_int
, psz_vod
);
1280 case VLM_STOP_MEDIA_INSTANCE
:
1281 id
= (int64_t)va_arg( args
, int64_t );
1282 psz_id
= (const char*)va_arg( args
, const char* );
1283 return vlm_ControlMediaInstanceStop( p_vlm
, id
, psz_id
);
1285 case VLM_PAUSE_MEDIA_INSTANCE
:
1286 id
= (int64_t)va_arg( args
, int64_t );
1287 psz_id
= (const char*)va_arg( args
, const char* );
1288 return vlm_ControlMediaInstancePause( p_vlm
, id
, psz_id
);
1290 case VLM_GET_MEDIA_INSTANCE_TIME
:
1291 id
= (int64_t)va_arg( args
, int64_t );
1292 psz_id
= (const char*)va_arg( args
, const char* );
1293 pi_i64
= (int64_t*)va_arg( args
, int64_t * );
1294 return vlm_ControlMediaInstanceGetTimePosition( p_vlm
, id
, psz_id
, pi_i64
, NULL
);
1295 case VLM_GET_MEDIA_INSTANCE_POSITION
:
1296 id
= (int64_t)va_arg( args
, int64_t );
1297 psz_id
= (const char*)va_arg( args
, const char* );
1298 pd_double
= (double*)va_arg( args
, double* );
1299 return vlm_ControlMediaInstanceGetTimePosition( p_vlm
, id
, psz_id
, NULL
, pd_double
);
1301 case VLM_SET_MEDIA_INSTANCE_TIME
:
1302 id
= (int64_t)va_arg( args
, int64_t );
1303 psz_id
= (const char*)va_arg( args
, const char* );
1304 i_i64
= (int64_t)va_arg( args
, int64_t);
1305 return vlm_ControlMediaInstanceSetTimePosition( p_vlm
, id
, psz_id
, i_i64
, -1 );
1306 case VLM_SET_MEDIA_INSTANCE_POSITION
:
1307 id
= (int64_t)va_arg( args
, int64_t );
1308 psz_id
= (const char*)va_arg( args
, const char* );
1309 d_double
= (double)va_arg( args
, double );
1310 return vlm_ControlMediaInstanceSetTimePosition( p_vlm
, id
, psz_id
, -1, d_double
);
1312 case VLM_CLEAR_SCHEDULES
:
1313 return vlm_ControlScheduleClear( p_vlm
);
1316 msg_Err( p_vlm
, "unknown VLM query" );
1317 return VLC_EGENERIC
;
1321 int vlm_ControlInternal( vlm_t
*p_vlm
, int i_query
, ... )
1326 va_start( args
, i_query
);
1327 i_result
= vlm_vaControlInternal( p_vlm
, i_query
, args
);
1333 int vlm_Control( vlm_t
*p_vlm
, int i_query
, ... )
1338 va_start( args
, i_query
);
1340 vlc_mutex_lock( &p_vlm
->lock
);
1341 i_result
= vlm_vaControlInternal( p_vlm
, i_query
, args
);
1342 vlc_mutex_unlock( &p_vlm
->lock
);