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() */
37 #include <time.h> /* ctime() */
40 #include <sys/time.h> /* gettimeofday() */
43 #include <vlc_modules.h>
45 #include <vlc_input.h>
46 #include <vlc_stream.h>
47 #include "vlm_internal.h"
48 #include "vlm_event.h"
52 #include "../stream_output/stream_output.h"
53 #include "../libvlc.h"
55 /*****************************************************************************
57 *****************************************************************************/
59 static void* Manage( void * );
60 static int vlm_MediaVodControl( void *, vod_media_t
*, const char *, int, va_list );
62 typedef struct preparse_data_t
68 static int InputEventPreparse( vlc_object_t
*p_this
, char const *psz_cmd
,
69 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
71 VLC_UNUSED(p_this
); VLC_UNUSED(psz_cmd
); VLC_UNUSED(oldval
);
72 preparse_data_t
*p_pre
= p_data
;
74 if( newval
.i_int
== INPUT_EVENT_DEAD
||
75 ( p_pre
->b_mux
&& newval
.i_int
== INPUT_EVENT_ITEM_META
) )
76 vlc_sem_post( p_pre
->p_sem
);
81 static int InputEvent( vlc_object_t
*p_this
, char const *psz_cmd
,
82 vlc_value_t oldval
, vlc_value_t newval
,
87 input_thread_t
*p_input
= (input_thread_t
*)p_this
;
88 vlm_t
*p_vlm
= libvlc_priv( p_input
->p_libvlc
)->p_vlm
;
90 vlm_media_sys_t
*p_media
= p_data
;
91 const char *psz_instance_name
= NULL
;
93 if( newval
.i_int
== INPUT_EVENT_STATE
)
95 for( int i
= 0; i
< p_media
->i_instance
; i
++ )
97 if( p_media
->instance
[i
]->p_input
== p_input
)
99 psz_instance_name
= p_media
->instance
[i
]->psz_name
;
103 vlm_SendEventMediaInstanceState( p_vlm
, p_media
->cfg
.id
, p_media
->cfg
.psz_name
, psz_instance_name
, var_GetInteger( p_input
, "state" ) );
105 vlc_mutex_lock( &p_vlm
->lock_manage
);
106 p_vlm
->input_state_changed
= true;
107 vlc_cond_signal( &p_vlm
->wait_manage
);
108 vlc_mutex_unlock( &p_vlm
->lock_manage
);
113 static vlc_mutex_t vlm_mutex
= VLC_STATIC_MUTEX
;
116 /*****************************************************************************
118 *****************************************************************************/
119 vlm_t
*vlm_New ( vlc_object_t
*p_this
)
121 vlm_t
*p_vlm
= NULL
, **pp_vlm
= &(libvlc_priv (p_this
->p_libvlc
)->p_vlm
);
124 /* Avoid multiple creation */
125 vlc_mutex_lock( &vlm_mutex
);
129 { /* VLM already exists */
130 if( likely( p_vlm
->users
< UINT_MAX
) )
134 vlc_mutex_unlock( &vlm_mutex
);
138 msg_Dbg( p_this
, "creating VLM" );
140 p_vlm
= vlc_custom_create( p_this
->p_libvlc
, sizeof( *p_vlm
),
144 vlc_mutex_unlock( &vlm_mutex
);
148 vlc_mutex_init( &p_vlm
->lock
);
149 vlc_mutex_init( &p_vlm
->lock_manage
);
150 vlc_cond_init_daytime( &p_vlm
->wait_manage
);
152 p_vlm
->input_state_changed
= false;
154 TAB_INIT( p_vlm
->i_media
, p_vlm
->media
);
155 TAB_INIT( p_vlm
->i_schedule
, p_vlm
->schedule
);
157 var_Create( p_vlm
, "intf-event", VLC_VAR_ADDRESS
);
159 if( vlc_clone( &p_vlm
->thread
, Manage
, p_vlm
, VLC_THREAD_PRIORITY_LOW
) )
161 vlc_cond_destroy( &p_vlm
->wait_manage
);
162 vlc_mutex_destroy( &p_vlm
->lock
);
163 vlc_mutex_destroy( &p_vlm
->lock_manage
);
164 vlc_object_release( p_vlm
);
165 vlc_mutex_unlock( &vlm_mutex
);
169 *pp_vlm
= p_vlm
; /* for future reference */
171 /* Load our configuration file */
172 psz_vlmconf
= var_CreateGetString( p_vlm
, "vlm-conf" );
173 if( psz_vlmconf
&& *psz_vlmconf
)
175 vlm_message_t
*p_message
= NULL
;
176 char *psz_buffer
= NULL
;
178 msg_Dbg( p_this
, "loading VLM configuration" );
179 if( asprintf(&psz_buffer
, "load %s", psz_vlmconf
) != -1 )
181 msg_Dbg( p_this
, "%s", psz_buffer
);
182 if( vlm_ExecuteCommand( p_vlm
, psz_buffer
, &p_message
) )
183 msg_Warn( p_this
, "error while loading the configuration file" );
185 vlm_MessageDelete( p_message
);
191 vlc_mutex_unlock( &vlm_mutex
);
196 /*****************************************************************************
198 *****************************************************************************/
199 void vlm_Delete( vlm_t
*p_vlm
)
201 /* vlm_Delete() is serialized against itself, and against vlm_New().
202 * This mutex protects libvlc_priv->p_vlm and p_vlm->users. */
203 vlc_mutex_lock( &vlm_mutex
);
204 assert( p_vlm
->users
> 0 );
205 if( --p_vlm
->users
== 0 )
206 assert( libvlc_priv(p_vlm
->p_libvlc
)->p_vlm
== p_vlm
);
212 vlc_mutex_unlock( &vlm_mutex
);
216 /* Destroy and release VLM */
217 vlc_mutex_lock( &p_vlm
->lock
);
218 vlm_ControlInternal( p_vlm
, VLM_CLEAR_MEDIAS
);
219 TAB_CLEAN( p_vlm
->i_media
, p_vlm
->media
);
221 vlm_ControlInternal( p_vlm
, VLM_CLEAR_SCHEDULES
);
222 TAB_CLEAN( p_vlm
->i_schedule
, p_vlm
->schedule
);
223 vlc_mutex_unlock( &p_vlm
->lock
);
225 vlc_cancel( p_vlm
->thread
);
229 module_unneed( p_vlm
->p_vod
, p_vlm
->p_vod
->p_module
);
230 vlc_object_release( p_vlm
->p_vod
);
233 libvlc_priv(p_vlm
->p_libvlc
)->p_vlm
= NULL
;
234 vlc_mutex_unlock( &vlm_mutex
);
236 vlc_join( p_vlm
->thread
, NULL
);
238 vlc_cond_destroy( &p_vlm
->wait_manage
);
239 vlc_mutex_destroy( &p_vlm
->lock
);
240 vlc_mutex_destroy( &p_vlm
->lock_manage
);
241 vlc_object_release( p_vlm
);
244 /*****************************************************************************
245 * vlm_ExecuteCommand:
246 *****************************************************************************/
247 int vlm_ExecuteCommand( vlm_t
*p_vlm
, const char *psz_command
,
248 vlm_message_t
**pp_message
)
252 vlc_mutex_lock( &p_vlm
->lock
);
253 i_result
= ExecuteCommand( p_vlm
, psz_command
, pp_message
);
254 vlc_mutex_unlock( &p_vlm
->lock
);
260 int64_t vlm_Date(void)
264 (void)gettimeofday( &tv
, NULL
);
265 return tv
.tv_sec
* INT64_C(1000000) + tv
.tv_usec
;
269 /*****************************************************************************
271 *****************************************************************************/
272 static int vlm_MediaVodControl( void *p_private
, vod_media_t
*p_vod_media
,
273 const char *psz_id
, int i_query
, va_list args
)
275 vlm_t
*vlm
= (vlm_t
*)p_private
;
280 if( !p_private
|| !p_vod_media
)
283 vlc_mutex_lock( &vlm
->lock
);
286 for( i
= 0, id
= -1; i
< vlm
->i_media
; i
++ )
288 if( p_vod_media
== vlm
->media
[i
]->vod
.p_media
)
290 id
= vlm
->media
[i
]->cfg
.id
;
296 vlc_mutex_unlock( &vlm
->lock
);
304 psz
= (const char *)va_arg( args
, const char * );
305 int64_t *i_time
= (int64_t *)va_arg( args
, int64_t *);
306 bool b_retry
= false;
309 /* No start time requested: return the current NPT */
310 i_ret
= vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_TIME
, id
, psz_id
, i_time
);
311 /* The instance is not running yet, it will start at 0 */
317 /* We want to seek before unpausing, but it won't
318 * work if the instance is not running yet. */
319 b_retry
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_TIME
, id
, psz_id
, *i_time
);
322 i_ret
= vlm_ControlInternal( vlm
, VLM_START_MEDIA_VOD_INSTANCE
, id
, psz_id
, 0, psz
);
324 if (!i_ret
&& b_retry
)
325 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_TIME
, id
, psz_id
, *i_time
);
329 case VOD_MEDIA_PAUSE
:
331 int64_t *i_time
= (int64_t *)va_arg( args
, int64_t *);
332 i_ret
= vlm_ControlInternal( vlm
, VLM_PAUSE_MEDIA_INSTANCE
, id
, psz_id
);
334 i_ret
= vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_TIME
, id
, psz_id
, i_time
);
339 i_ret
= vlm_ControlInternal( vlm
, VLM_STOP_MEDIA_INSTANCE
, id
, psz_id
);
344 int64_t i_time
= (int64_t)va_arg( args
, int64_t );
345 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_TIME
, id
, psz_id
, i_time
);
349 case VOD_MEDIA_REWIND
:
351 double d_scale
= (double)va_arg( args
, double );
354 vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, &d_position
);
355 d_position
-= (d_scale
/ 1000.0);
356 if( d_position
< 0.0 )
358 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, d_position
);
362 case VOD_MEDIA_FORWARD
:
364 double d_scale
= (double)va_arg( args
, double );
367 vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, &d_position
);
368 d_position
+= (d_scale
/ 1000.0);
369 if( d_position
> 1.0 )
371 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, d_position
);
376 i_ret
= VLC_EGENERIC
;
380 vlc_mutex_unlock( &vlm
->lock
);
386 /*****************************************************************************
388 *****************************************************************************/
389 static void* Manage( void* p_object
)
391 vlm_t
*vlm
= (vlm_t
*)p_object
;
395 mtime_t i_nextschedule
= 0;
397 i_lastcheck
= vlm_Date();
401 char **ppsz_scheduled_commands
= NULL
;
402 int i_scheduled_commands
= 0;
403 bool scheduled_command
= false;
405 vlc_mutex_lock( &vlm
->lock_manage
);
406 mutex_cleanup_push( &vlm
->lock_manage
);
407 while( !vlm
->input_state_changed
&& !scheduled_command
)
410 scheduled_command
= vlc_cond_timedwait( &vlm
->wait_manage
, &vlm
->lock_manage
, i_nextschedule
) != 0;
412 vlc_cond_wait( &vlm
->wait_manage
, &vlm
->lock_manage
);
414 vlm
->input_state_changed
= false;
417 int canc
= vlc_savecancel ();
418 /* destroy the inputs that wants to die, and launch the next input */
419 vlc_mutex_lock( &vlm
->lock
);
420 for( i
= 0; i
< vlm
->i_media
; i
++ )
422 vlm_media_sys_t
*p_media
= vlm
->media
[i
];
424 for( j
= 0; j
< p_media
->i_instance
; )
426 vlm_media_instance_sys_t
*p_instance
= p_media
->instance
[j
];
428 if( p_instance
->p_input
&& ( p_instance
->p_input
->b_eof
|| p_instance
->p_input
->b_error
) )
430 int i_new_input_index
;
433 i_new_input_index
= p_instance
->i_index
+ 1;
434 if( !p_media
->cfg
.b_vod
&& p_media
->cfg
.broadcast
.b_loop
&& i_new_input_index
>= p_media
->cfg
.i_input
)
435 i_new_input_index
= 0;
437 /* FIXME implement multiple input with VOD */
438 if( p_media
->cfg
.b_vod
|| i_new_input_index
>= p_media
->cfg
.i_input
)
439 vlm_ControlInternal( vlm
, VLM_STOP_MEDIA_INSTANCE
, p_media
->cfg
.id
, p_instance
->psz_name
);
441 vlm_ControlInternal( vlm
, VLM_START_MEDIA_BROADCAST_INSTANCE
, p_media
->cfg
.id
, p_instance
->psz_name
, i_new_input_index
);
456 for( i
= 0; i
< vlm
->i_schedule
; i
++ )
458 mtime_t i_real_date
= vlm
->schedule
[i
]->i_date
;
460 if( vlm
->schedule
[i
]->b_enabled
)
462 if( vlm
->schedule
[i
]->i_date
== 0 ) // now !
464 vlm
->schedule
[i
]->i_date
= (i_time
/ 1000000) * 1000000 ;
465 i_real_date
= i_time
;
467 else if( vlm
->schedule
[i
]->i_period
!= 0 )
470 while( vlm
->schedule
[i
]->i_date
+ j
*
471 vlm
->schedule
[i
]->i_period
<= i_lastcheck
&&
472 ( vlm
->schedule
[i
]->i_repeat
> j
||
473 vlm
->schedule
[i
]->i_repeat
== -1 ) )
478 i_real_date
= vlm
->schedule
[i
]->i_date
+ j
*
479 vlm
->schedule
[i
]->i_period
;
482 if( i_real_date
<= i_time
)
484 if( i_real_date
> i_lastcheck
)
486 for( j
= 0; j
< vlm
->schedule
[i
]->i_command
; j
++ )
488 TAB_APPEND( i_scheduled_commands
,
489 ppsz_scheduled_commands
,
490 strdup(vlm
->schedule
[i
]->command
[j
] ) );
494 else if( i_nextschedule
== 0 || i_real_date
< i_nextschedule
)
496 i_nextschedule
= i_real_date
;
501 while( i_scheduled_commands
)
503 vlm_message_t
*message
= NULL
;
504 char *psz_command
= ppsz_scheduled_commands
[0];
505 ExecuteCommand( vlm
, psz_command
,&message
);
507 /* for now, drop the message */
508 vlm_MessageDelete( message
);
509 TAB_REMOVE( i_scheduled_commands
,
510 ppsz_scheduled_commands
,
515 i_lastcheck
= i_time
;
516 vlc_mutex_unlock( &vlm
->lock
);
517 vlc_restorecancel (canc
);
530 int i_connection_count;
531 int i_connection_active;
540 } vlm_media_status_t;
544 static vlm_media_sys_t
*vlm_ControlMediaGetById( vlm_t
*p_vlm
, int64_t id
)
548 for( i
= 0; i
< p_vlm
->i_media
; i
++ )
550 if( p_vlm
->media
[i
]->cfg
.id
== id
)
551 return p_vlm
->media
[i
];
555 static vlm_media_sys_t
*vlm_ControlMediaGetByName( vlm_t
*p_vlm
, const char *psz_name
)
559 for( i
= 0; i
< p_vlm
->i_media
; i
++ )
561 if( !strcmp( p_vlm
->media
[i
]->cfg
.psz_name
, psz_name
) )
562 return p_vlm
->media
[i
];
566 static int vlm_MediaDescriptionCheck( vlm_t
*p_vlm
, vlm_media_t
*p_cfg
)
570 if( !p_cfg
|| !p_cfg
->psz_name
||
571 !strcmp( p_cfg
->psz_name
, "all" ) || !strcmp( p_cfg
->psz_name
, "media" ) || !strcmp( p_cfg
->psz_name
, "schedule" ) )
574 for( i
= 0; i
< p_vlm
->i_media
; i
++ )
576 if( p_vlm
->media
[i
]->cfg
.id
== p_cfg
->id
)
578 if( !strcmp( p_vlm
->media
[i
]->cfg
.psz_name
, p_cfg
->psz_name
) )
585 /* Called after a media description is changed/added */
586 static int vlm_OnMediaUpdate( vlm_t
*p_vlm
, vlm_media_sys_t
*p_media
)
588 vlm_media_t
*p_cfg
= &p_media
->cfg
;
589 /* Check if we need to create/delete a vod media */
590 if( p_cfg
->b_vod
&& p_vlm
->p_vod
)
592 if( !p_cfg
->b_enabled
&& p_media
->vod
.p_media
)
594 p_vlm
->p_vod
->pf_media_del( p_vlm
->p_vod
, p_media
->vod
.p_media
);
595 p_media
->vod
.p_media
= NULL
;
597 else if( p_cfg
->b_enabled
&& !p_media
->vod
.p_media
&& p_cfg
->i_input
)
599 /* Pre-parse the input */
600 input_thread_t
*p_input
;
606 vlc_gc_decref( p_media
->vod
.p_item
);
608 if( strstr( p_cfg
->ppsz_input
[0], "://" ) == NULL
)
610 char *psz_uri
= vlc_path2uri( p_cfg
->ppsz_input
[0], NULL
);
611 p_media
->vod
.p_item
= input_item_New( psz_uri
,
616 p_media
->vod
.p_item
= input_item_New( p_cfg
->ppsz_input
[0],
619 if( p_cfg
->psz_output
)
621 if( asprintf( &psz_output
, "%s:description", p_cfg
->psz_output
) == -1 )
625 psz_output
= strdup( "#description" );
627 if( psz_output
&& asprintf( &psz_dup
, "sout=%s", psz_output
) != -1 )
629 input_item_AddOption( p_media
->vod
.p_item
, psz_dup
, VLC_INPUT_OPTION_TRUSTED
);
634 for( i
= 0; i
< p_cfg
->i_option
; i
++ )
635 input_item_AddOption( p_media
->vod
.p_item
,
636 p_cfg
->ppsz_option
[i
], VLC_INPUT_OPTION_TRUSTED
);
638 if( asprintf( &psz_header
, _("Media: %s"), p_cfg
->psz_name
) == -1 )
641 sout_description_data_t data
;
642 TAB_INIT(data
.i_es
, data
.es
);
644 p_input
= input_Create( p_vlm
->p_vod
, p_media
->vod
.p_item
, psz_header
, NULL
);
647 vlc_sem_t sem_preparse
;
648 vlc_sem_init( &sem_preparse
, 0 );
650 preparse_data_t preparse
= { .p_sem
= &sem_preparse
,
651 .b_mux
= (p_cfg
->vod
.psz_mux
!= NULL
) };
652 var_AddCallback( p_input
, "intf-event", InputEventPreparse
,
655 data
.sem
= &sem_preparse
;
656 var_Create( p_input
, "sout-description-data", VLC_VAR_ADDRESS
);
657 var_SetAddress( p_input
, "sout-description-data", &data
);
659 if( !input_Start( p_input
) )
660 vlc_sem_wait( &sem_preparse
);
662 var_DelCallback( p_input
, "intf-event", InputEventPreparse
,
665 input_Stop( p_input
, true );
666 input_Close( p_input
);
667 vlc_sem_destroy( &sem_preparse
);
671 /* XXX: Don't do it that way, but properly use a new input item ref. */
672 input_item_t item
= *p_media
->vod
.p_item
;;
673 if( p_cfg
->vod
.psz_mux
)
676 if (!strcmp(p_cfg
->vod
.psz_mux
, "ps"))
678 else if (!strcmp(p_cfg
->vod
.psz_mux
, "ts"))
681 psz_mux
= p_cfg
->vod
.psz_mux
;
683 es_format_t es
, *p_es
= &es
;
686 unsigned char utext
[5];
690 sprintf( fourcc
.text
, "%4.4s", psz_mux
);
691 for( int i
= 0; i
< 4; i
++ )
692 fourcc
.utext
[i
] = tolower(fourcc
.utext
[i
]);
696 es_format_Init( &es
, VIDEO_ES
, fourcc
.value
);
700 item
.i_es
= data
.i_es
;
703 p_media
->vod
.p_media
= p_vlm
->p_vod
->pf_media_new( p_vlm
->p_vod
,
704 p_cfg
->psz_name
, &item
);
706 TAB_CLEAN(data
.i_es
, data
.es
);
709 else if ( p_cfg
->b_vod
)
710 msg_Err( p_vlm
, "vod server is not loaded" );
713 /* TODO start media if needed */
716 /* TODO add support of var vlm_media_broadcast/vlm_media_vod */
718 vlm_SendEventMediaChanged( p_vlm
, p_cfg
->id
, p_cfg
->psz_name
);
721 static int vlm_ControlMediaChange( vlm_t
*p_vlm
, vlm_media_t
*p_cfg
)
723 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, p_cfg
->id
);
726 if( !p_media
|| vlm_MediaDescriptionCheck( p_vlm
, p_cfg
) )
728 if( ( p_media
->cfg
.b_vod
&& !p_cfg
->b_vod
) || ( !p_media
->cfg
.b_vod
&& p_cfg
->b_vod
) )
733 /* TODO check what are the changes being done (stop instance if needed) */
736 vlm_media_Clean( &p_media
->cfg
);
737 vlm_media_Copy( &p_media
->cfg
, p_cfg
);
739 return vlm_OnMediaUpdate( p_vlm
, p_media
);
742 static int vlm_ControlMediaAdd( vlm_t
*p_vlm
, vlm_media_t
*p_cfg
, int64_t *p_id
)
744 vlm_media_sys_t
*p_media
;
746 if( vlm_MediaDescriptionCheck( p_vlm
, p_cfg
) || vlm_ControlMediaGetByName( p_vlm
, p_cfg
->psz_name
) )
748 msg_Err( p_vlm
, "invalid media description" );
751 /* Check if we need to load the VOD server */
752 if( p_cfg
->b_vod
&& !p_vlm
->p_vod
)
754 p_vlm
->p_vod
= vlc_custom_create( VLC_OBJECT(p_vlm
), sizeof( vod_t
),
756 p_vlm
->p_vod
->p_module
= module_need( p_vlm
->p_vod
, "vod server", "$vod-server", false );
757 if( !p_vlm
->p_vod
->p_module
)
759 msg_Err( p_vlm
, "cannot find vod server" );
760 vlc_object_release( p_vlm
->p_vod
);
765 p_vlm
->p_vod
->p_data
= p_vlm
;
766 p_vlm
->p_vod
->pf_media_control
= vlm_MediaVodControl
;
769 p_media
= calloc( 1, sizeof( vlm_media_sys_t
) );
773 vlm_media_Copy( &p_media
->cfg
, p_cfg
);
774 p_media
->cfg
.id
= p_vlm
->i_id
++;
775 /* FIXME do we do something here if enabled is true ? */
777 p_media
->vod
.p_item
= input_item_New( NULL
, NULL
);
779 p_media
->vod
.p_media
= NULL
;
780 TAB_INIT( p_media
->i_instance
, p_media
->instance
);
783 TAB_APPEND( p_vlm
->i_media
, p_vlm
->media
, p_media
);
786 *p_id
= p_media
->cfg
.id
;
789 vlm_SendEventMediaAdded( p_vlm
, p_media
->cfg
.id
, p_media
->cfg
.psz_name
);
790 return vlm_OnMediaUpdate( p_vlm
, p_media
);
793 static int vlm_ControlMediaDel( vlm_t
*p_vlm
, int64_t id
)
795 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
800 while( p_media
->i_instance
> 0 )
801 vlm_ControlInternal( p_vlm
, VLM_STOP_MEDIA_INSTANCE
, id
, p_media
->instance
[0]->psz_name
);
803 if( p_media
->cfg
.b_vod
)
805 p_media
->cfg
.b_enabled
= false;
806 vlm_OnMediaUpdate( p_vlm
, p_media
);
810 vlm_SendEventMediaRemoved( p_vlm
, id
, p_media
->cfg
.psz_name
);
812 vlm_media_Clean( &p_media
->cfg
);
814 vlc_gc_decref( p_media
->vod
.p_item
);
816 if( p_media
->vod
.p_media
)
817 p_vlm
->p_vod
->pf_media_del( p_vlm
->p_vod
, p_media
->vod
.p_media
);
819 TAB_REMOVE( p_vlm
->i_media
, p_vlm
->media
, p_media
);
825 static int vlm_ControlMediaGets( vlm_t
*p_vlm
, vlm_media_t
***ppp_dsc
, int *pi_dsc
)
827 vlm_media_t
**pp_dsc
;
831 TAB_INIT( i_dsc
, pp_dsc
);
832 for( i
= 0; i
< p_vlm
->i_media
; i
++ )
834 vlm_media_t
*p_dsc
= vlm_media_Duplicate( &p_vlm
->media
[i
]->cfg
);
835 TAB_APPEND( i_dsc
, pp_dsc
, p_dsc
);
843 static int vlm_ControlMediaClear( vlm_t
*p_vlm
)
845 while( p_vlm
->i_media
> 0 )
846 vlm_ControlMediaDel( p_vlm
, p_vlm
->media
[0]->cfg
.id
);
850 static int vlm_ControlMediaGet( vlm_t
*p_vlm
, int64_t id
, vlm_media_t
**pp_dsc
)
852 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
856 *pp_dsc
= vlm_media_Duplicate( &p_media
->cfg
);
859 static int vlm_ControlMediaGetId( vlm_t
*p_vlm
, const char *psz_name
, int64_t *p_id
)
861 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetByName( p_vlm
, psz_name
);
865 *p_id
= p_media
->cfg
.id
;
869 static vlm_media_instance_sys_t
*vlm_ControlMediaInstanceGetByName( vlm_media_sys_t
*p_media
, const char *psz_id
)
873 for( i
= 0; i
< p_media
->i_instance
; i
++ )
875 const char *psz
= p_media
->instance
[i
]->psz_name
;
876 if( ( psz
== NULL
&& psz_id
== NULL
) ||
877 ( psz
&& psz_id
&& !strcmp( psz
, psz_id
) ) )
878 return p_media
->instance
[i
];
882 static vlm_media_instance_sys_t
*vlm_MediaInstanceNew( vlm_t
*p_vlm
, const char *psz_name
)
884 vlm_media_instance_sys_t
*p_instance
= calloc( 1, sizeof(vlm_media_instance_sys_t
) );
888 p_instance
->psz_name
= NULL
;
890 p_instance
->psz_name
= strdup( psz_name
);
892 p_instance
->p_item
= input_item_New( NULL
, NULL
);
894 p_instance
->i_index
= 0;
895 p_instance
->b_sout_keep
= false;
896 p_instance
->p_parent
= vlc_object_create( p_vlm
, sizeof (vlc_object_t
) );
897 p_instance
->p_input
= NULL
;
898 p_instance
->p_input_resource
= input_resource_New( p_instance
->p_parent
);
902 static void vlm_MediaInstanceDelete( vlm_t
*p_vlm
, int64_t id
, vlm_media_instance_sys_t
*p_instance
, vlm_media_sys_t
*p_media
)
904 input_thread_t
*p_input
= p_instance
->p_input
;
907 input_Stop( p_input
, true );
908 input_Join( p_input
);
909 var_DelCallback( p_instance
->p_input
, "intf-event", InputEvent
, p_media
);
910 input_Release( p_input
);
912 vlm_SendEventMediaInstanceStopped( p_vlm
, id
, p_media
->cfg
.psz_name
);
914 input_resource_Terminate( p_instance
->p_input_resource
);
915 input_resource_Release( p_instance
->p_input_resource
);
916 vlc_object_release( p_instance
->p_parent
);
918 TAB_REMOVE( p_media
->i_instance
, p_media
->instance
, p_instance
);
919 vlc_gc_decref( p_instance
->p_item
);
920 free( p_instance
->psz_name
);
925 static int vlm_ControlMediaInstanceStart( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
, int i_input_index
, const char *psz_vod_output
)
927 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
928 vlm_media_instance_sys_t
*p_instance
;
931 if( !p_media
|| !p_media
->cfg
.b_enabled
|| p_media
->cfg
.i_input
<= 0 )
934 /* TODO support multiple input for VOD with sout-keep ? */
936 if( ( p_media
->cfg
.b_vod
&& !psz_vod_output
) || ( !p_media
->cfg
.b_vod
&& psz_vod_output
) )
939 if( i_input_index
< 0 || i_input_index
>= p_media
->cfg
.i_input
)
942 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
945 vlm_media_t
*p_cfg
= &p_media
->cfg
;
948 p_instance
= vlm_MediaInstanceNew( p_vlm
, psz_id
);
954 var_Create( p_instance
->p_parent
, "vod-media", VLC_VAR_ADDRESS
);
955 var_SetAddress( p_instance
->p_parent
, "vod-media",
956 p_media
->vod
.p_media
);
957 var_Create( p_instance
->p_parent
, "vod-session", VLC_VAR_STRING
);
958 var_SetString( p_instance
->p_parent
, "vod-session", psz_id
);
961 if( p_cfg
->psz_output
!= NULL
|| psz_vod_output
!= NULL
)
964 if( asprintf( &psz_buffer
, "sout=%s%s%s",
965 p_cfg
->psz_output
? p_cfg
->psz_output
: "",
966 (p_cfg
->psz_output
&& psz_vod_output
) ? ":" : psz_vod_output
? "#" : "",
967 psz_vod_output
? psz_vod_output
: "" ) != -1 )
969 input_item_AddOption( p_instance
->p_item
, psz_buffer
, VLC_INPUT_OPTION_TRUSTED
);
974 for( i
= 0; i
< p_cfg
->i_option
; i
++ )
976 if( !strcmp( p_cfg
->ppsz_option
[i
], "sout-keep" ) )
977 p_instance
->b_sout_keep
= true;
978 else if( !strcmp( p_cfg
->ppsz_option
[i
], "nosout-keep" ) || !strcmp( p_cfg
->ppsz_option
[i
], "no-sout-keep" ) )
979 p_instance
->b_sout_keep
= false;
981 input_item_AddOption( p_instance
->p_item
, p_cfg
->ppsz_option
[i
], VLC_INPUT_OPTION_TRUSTED
);
983 TAB_APPEND( p_media
->i_instance
, p_media
->instance
, p_instance
);
986 /* Stop old instance */
987 input_thread_t
*p_input
= p_instance
->p_input
;
990 if( p_instance
->i_index
== i_input_index
&&
991 !p_input
->b_eof
&& !p_input
->b_error
)
993 if( var_GetInteger( p_input
, "state" ) == PAUSE_S
)
994 var_SetInteger( p_input
, "state", PLAYING_S
);
999 input_Stop( p_input
, true );
1000 input_Join( p_input
);
1001 var_DelCallback( p_instance
->p_input
, "intf-event", InputEvent
, p_media
);
1002 input_Release( p_input
);
1004 if( !p_instance
->b_sout_keep
)
1005 input_resource_TerminateSout( p_instance
->p_input_resource
);
1006 input_resource_TerminateVout( p_instance
->p_input_resource
);
1008 vlm_SendEventMediaInstanceStopped( p_vlm
, id
, p_media
->cfg
.psz_name
);
1012 p_instance
->i_index
= i_input_index
;
1013 if( strstr( p_media
->cfg
.ppsz_input
[p_instance
->i_index
], "://" ) == NULL
)
1015 char *psz_uri
= vlc_path2uri(
1016 p_media
->cfg
.ppsz_input
[p_instance
->i_index
], NULL
);
1017 input_item_SetURI( p_instance
->p_item
, psz_uri
) ;
1021 input_item_SetURI( p_instance
->p_item
, p_media
->cfg
.ppsz_input
[p_instance
->i_index
] ) ;
1023 if( asprintf( &psz_log
, _("Media: %s"), p_media
->cfg
.psz_name
) != -1 )
1025 p_instance
->p_input
= input_Create( p_instance
->p_parent
,
1026 p_instance
->p_item
, psz_log
,
1027 p_instance
->p_input_resource
);
1028 if( p_instance
->p_input
)
1030 var_AddCallback( p_instance
->p_input
, "intf-event", InputEvent
, p_media
);
1032 if( input_Start( p_instance
->p_input
) != VLC_SUCCESS
)
1034 var_DelCallback( p_instance
->p_input
, "intf-event", InputEvent
, p_media
);
1035 vlc_object_release( p_instance
->p_input
);
1036 p_instance
->p_input
= NULL
;
1040 if( !p_instance
->p_input
)
1042 vlm_MediaInstanceDelete( p_vlm
, id
, p_instance
, p_media
);
1046 vlm_SendEventMediaInstanceStarted( p_vlm
, id
, p_media
->cfg
.psz_name
);
1054 static int vlm_ControlMediaInstanceStop( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
)
1056 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1057 vlm_media_instance_sys_t
*p_instance
;
1060 return VLC_EGENERIC
;
1062 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
1064 return VLC_EGENERIC
;
1066 vlm_MediaInstanceDelete( p_vlm
, id
, p_instance
, p_media
);
1070 static int vlm_ControlMediaInstancePause( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
)
1072 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1073 vlm_media_instance_sys_t
*p_instance
;
1077 return VLC_EGENERIC
;
1079 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
1080 if( !p_instance
|| !p_instance
->p_input
)
1081 return VLC_EGENERIC
;
1083 /* Toggle pause state */
1084 i_state
= var_GetInteger( p_instance
->p_input
, "state" );
1085 if( i_state
== PAUSE_S
&& !p_media
->cfg
.b_vod
)
1086 var_SetInteger( p_instance
->p_input
, "state", PLAYING_S
);
1087 else if( i_state
== PLAYING_S
)
1088 var_SetInteger( p_instance
->p_input
, "state", PAUSE_S
);
1091 static int vlm_ControlMediaInstanceGetTimePosition( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
, int64_t *pi_time
, double *pd_position
)
1093 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1094 vlm_media_instance_sys_t
*p_instance
;
1097 return VLC_EGENERIC
;
1099 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
1100 if( !p_instance
|| !p_instance
->p_input
)
1101 return VLC_EGENERIC
;
1104 *pi_time
= var_GetTime( p_instance
->p_input
, "time" );
1106 *pd_position
= var_GetFloat( p_instance
->p_input
, "position" );
1109 static int vlm_ControlMediaInstanceSetTimePosition( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
, int64_t i_time
, double d_position
)
1111 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1112 vlm_media_instance_sys_t
*p_instance
;
1115 return VLC_EGENERIC
;
1117 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
1118 if( !p_instance
|| !p_instance
->p_input
)
1119 return VLC_EGENERIC
;
1122 return var_SetTime( p_instance
->p_input
, "time", i_time
);
1123 else if( d_position
>= 0 && d_position
<= 100 )
1124 return var_SetFloat( p_instance
->p_input
, "position", d_position
);
1125 return VLC_EGENERIC
;
1128 static int vlm_ControlMediaInstanceGets( vlm_t
*p_vlm
, int64_t id
, vlm_media_instance_t
***ppp_idsc
, int *pi_instance
)
1130 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1131 vlm_media_instance_t
**pp_idsc
;
1136 return VLC_EGENERIC
;
1138 TAB_INIT( i_idsc
, pp_idsc
);
1139 for( i
= 0; i
< p_media
->i_instance
; i
++ )
1141 vlm_media_instance_sys_t
*p_instance
= p_media
->instance
[i
];
1142 vlm_media_instance_t
*p_idsc
= vlm_media_instance_New();
1144 if( p_instance
->psz_name
)
1145 p_idsc
->psz_name
= strdup( p_instance
->psz_name
);
1146 if( p_instance
->p_input
)
1148 p_idsc
->i_time
= var_GetTime( p_instance
->p_input
, "time" );
1149 p_idsc
->i_length
= var_GetTime( p_instance
->p_input
, "length" );
1150 p_idsc
->d_position
= var_GetFloat( p_instance
->p_input
, "position" );
1151 if( var_GetInteger( p_instance
->p_input
, "state" ) == PAUSE_S
)
1152 p_idsc
->b_paused
= true;
1153 p_idsc
->i_rate
= INPUT_RATE_DEFAULT
1154 / var_GetFloat( p_instance
->p_input
, "rate" );
1157 TAB_APPEND( i_idsc
, pp_idsc
, p_idsc
);
1159 *ppp_idsc
= pp_idsc
;
1160 *pi_instance
= i_idsc
;
1164 static int vlm_ControlMediaInstanceClear( vlm_t
*p_vlm
, int64_t id
)
1166 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1169 return VLC_EGENERIC
;
1171 while( p_media
->i_instance
> 0 )
1172 vlm_ControlMediaInstanceStop( p_vlm
, id
, p_media
->instance
[0]->psz_name
);
1177 static int vlm_ControlScheduleClear( vlm_t
*p_vlm
)
1179 while( p_vlm
->i_schedule
> 0 )
1180 vlm_ScheduleDelete( p_vlm
, p_vlm
->schedule
[0] );
1185 static int vlm_vaControlInternal( vlm_t
*p_vlm
, int i_query
, va_list args
)
1188 vlm_media_t
**pp_dsc
;
1189 vlm_media_t
***ppp_dsc
;
1190 vlm_media_instance_t
***ppp_idsc
;
1192 const char *psz_vod
;
1206 case VLM_GET_MEDIAS
:
1207 ppp_dsc
= (vlm_media_t
***)va_arg( args
, vlm_media_t
*** );
1208 pi_int
= (int *)va_arg( args
, int * );
1209 return vlm_ControlMediaGets( p_vlm
, ppp_dsc
, pi_int
);
1211 case VLM_CLEAR_MEDIAS
:
1212 return vlm_ControlMediaClear( p_vlm
);
1214 case VLM_CHANGE_MEDIA
:
1215 p_dsc
= (vlm_media_t
*)va_arg( args
, vlm_media_t
* );
1216 return vlm_ControlMediaChange( p_vlm
, p_dsc
);
1219 p_dsc
= (vlm_media_t
*)va_arg( args
, vlm_media_t
* );
1220 p_id
= (int64_t*)va_arg( args
, int64_t * );
1221 return vlm_ControlMediaAdd( p_vlm
, p_dsc
, p_id
);
1224 id
= (int64_t)va_arg( args
, int64_t );
1225 return vlm_ControlMediaDel( p_vlm
, id
);
1228 id
= (int64_t)va_arg( args
, int64_t );
1229 pp_dsc
= (vlm_media_t
**)va_arg( args
, vlm_media_t
** );
1230 return vlm_ControlMediaGet( p_vlm
, id
, pp_dsc
);
1232 case VLM_GET_MEDIA_ID
:
1233 psz_id
= (const char*)va_arg( args
, const char * );
1234 p_id
= (int64_t*)va_arg( args
, int64_t * );
1235 return vlm_ControlMediaGetId( p_vlm
, psz_id
, p_id
);
1238 /* Media instance control */
1239 case VLM_GET_MEDIA_INSTANCES
:
1240 id
= (int64_t)va_arg( args
, int64_t );
1241 ppp_idsc
= (vlm_media_instance_t
***)va_arg( args
, vlm_media_instance_t
*** );
1242 pi_int
= (int *)va_arg( args
, int *);
1243 return vlm_ControlMediaInstanceGets( p_vlm
, id
, ppp_idsc
, pi_int
);
1245 case VLM_CLEAR_MEDIA_INSTANCES
:
1246 id
= (int64_t)va_arg( args
, int64_t );
1247 return vlm_ControlMediaInstanceClear( p_vlm
, id
);
1250 case VLM_START_MEDIA_BROADCAST_INSTANCE
:
1251 id
= (int64_t)va_arg( args
, int64_t );
1252 psz_id
= (const char*)va_arg( args
, const char* );
1253 i_int
= (int)va_arg( args
, int );
1254 return vlm_ControlMediaInstanceStart( p_vlm
, id
, psz_id
, i_int
, NULL
);
1256 case VLM_START_MEDIA_VOD_INSTANCE
:
1257 id
= (int64_t)va_arg( args
, int64_t );
1258 psz_id
= (const char*)va_arg( args
, const char* );
1259 i_int
= (int)va_arg( args
, int );
1260 psz_vod
= (const char*)va_arg( args
, const char* );
1262 return VLC_EGENERIC
;
1263 return vlm_ControlMediaInstanceStart( p_vlm
, id
, psz_id
, i_int
, psz_vod
);
1265 case VLM_STOP_MEDIA_INSTANCE
:
1266 id
= (int64_t)va_arg( args
, int64_t );
1267 psz_id
= (const char*)va_arg( args
, const char* );
1268 return vlm_ControlMediaInstanceStop( p_vlm
, id
, psz_id
);
1270 case VLM_PAUSE_MEDIA_INSTANCE
:
1271 id
= (int64_t)va_arg( args
, int64_t );
1272 psz_id
= (const char*)va_arg( args
, const char* );
1273 return vlm_ControlMediaInstancePause( p_vlm
, id
, psz_id
);
1275 case VLM_GET_MEDIA_INSTANCE_TIME
:
1276 id
= (int64_t)va_arg( args
, int64_t );
1277 psz_id
= (const char*)va_arg( args
, const char* );
1278 pi_i64
= (int64_t*)va_arg( args
, int64_t * );
1279 return vlm_ControlMediaInstanceGetTimePosition( p_vlm
, id
, psz_id
, pi_i64
, NULL
);
1280 case VLM_GET_MEDIA_INSTANCE_POSITION
:
1281 id
= (int64_t)va_arg( args
, int64_t );
1282 psz_id
= (const char*)va_arg( args
, const char* );
1283 pd_double
= (double*)va_arg( args
, double* );
1284 return vlm_ControlMediaInstanceGetTimePosition( p_vlm
, id
, psz_id
, NULL
, pd_double
);
1286 case VLM_SET_MEDIA_INSTANCE_TIME
:
1287 id
= (int64_t)va_arg( args
, int64_t );
1288 psz_id
= (const char*)va_arg( args
, const char* );
1289 i_i64
= (int64_t)va_arg( args
, int64_t);
1290 return vlm_ControlMediaInstanceSetTimePosition( p_vlm
, id
, psz_id
, i_i64
, -1 );
1291 case VLM_SET_MEDIA_INSTANCE_POSITION
:
1292 id
= (int64_t)va_arg( args
, int64_t );
1293 psz_id
= (const char*)va_arg( args
, const char* );
1294 d_double
= (double)va_arg( args
, double );
1295 return vlm_ControlMediaInstanceSetTimePosition( p_vlm
, id
, psz_id
, -1, d_double
);
1297 case VLM_CLEAR_SCHEDULES
:
1298 return vlm_ControlScheduleClear( p_vlm
);
1301 msg_Err( p_vlm
, "unknown VLM query" );
1302 return VLC_EGENERIC
;
1306 int vlm_ControlInternal( vlm_t
*p_vlm
, int i_query
, ... )
1311 va_start( args
, i_query
);
1312 i_result
= vlm_vaControlInternal( p_vlm
, i_query
, args
);
1318 int vlm_Control( vlm_t
*p_vlm
, int i_query
, ... )
1323 va_start( args
, i_query
);
1325 vlc_mutex_lock( &p_vlm
->lock
);
1326 i_result
= vlm_vaControlInternal( p_vlm
, i_query
, args
);
1327 vlc_mutex_unlock( &p_vlm
->lock
);