1 /*****************************************************************************
2 * vlm.c: VLM interface plugin
3 *****************************************************************************
4 * Copyright (C) 2000-2005 VLC authors and VideoLAN
6 * Authors: Simon Latapie <garf@videolan.org>
7 * Laurent Aimar <fenrir@videolan.org>
8 * Gildas Bazin <gbazin@videolan.org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
32 #include <vlc_common.h>
35 #include <ctype.h> /* tolower() */
36 #include <time.h> /* ctime() */
41 #include <vlc_modules.h>
43 #include <vlc_input.h>
44 #include <vlc_stream.h>
45 #include "vlm_internal.h"
46 #include "vlm_event.h"
50 #include "../stream_output/stream_output.h"
51 #include "../libvlc.h"
53 /*****************************************************************************
55 *****************************************************************************/
57 static void* Manage( void * );
58 static int vlm_MediaVodControl( void *, vod_media_t
*, const char *, int, va_list );
60 typedef struct preparse_data_t
66 static int InputEventPreparse( vlc_object_t
*p_this
, char const *psz_cmd
,
67 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
69 VLC_UNUSED(p_this
); VLC_UNUSED(psz_cmd
); VLC_UNUSED(oldval
);
70 preparse_data_t
*p_pre
= p_data
;
72 if( newval
.i_int
== INPUT_EVENT_DEAD
||
73 ( p_pre
->b_mux
&& newval
.i_int
== INPUT_EVENT_ITEM_META
) )
74 vlc_sem_post( p_pre
->p_sem
);
79 static int InputEvent( vlc_object_t
*p_this
, char const *psz_cmd
,
80 vlc_value_t oldval
, vlc_value_t newval
,
85 input_thread_t
*p_input
= (input_thread_t
*)p_this
;
86 vlm_t
*p_vlm
= libvlc_priv( p_input
->obj
.libvlc
)->p_vlm
;
88 vlm_media_sys_t
*p_media
= p_data
;
89 const char *psz_instance_name
= NULL
;
91 if( newval
.i_int
== INPUT_EVENT_STATE
)
93 for( int i
= 0; i
< p_media
->i_instance
; i
++ )
95 if( p_media
->instance
[i
]->p_input
== p_input
)
97 psz_instance_name
= p_media
->instance
[i
]->psz_name
;
101 vlm_SendEventMediaInstanceState( p_vlm
, p_media
->cfg
.id
, p_media
->cfg
.psz_name
, psz_instance_name
, var_GetInteger( p_input
, "state" ) );
103 vlc_mutex_lock( &p_vlm
->lock_manage
);
104 p_vlm
->input_state_changed
= true;
105 vlc_cond_signal( &p_vlm
->wait_manage
);
106 vlc_mutex_unlock( &p_vlm
->lock_manage
);
111 static vlc_mutex_t vlm_mutex
= VLC_STATIC_MUTEX
;
113 /*****************************************************************************
115 *****************************************************************************/
116 vlm_t
*vlm_New( libvlc_int_t
*libvlc
, const char *psz_vlmconf
)
118 vlm_t
*p_vlm
= NULL
, **pp_vlm
= &(libvlc_priv(libvlc
)->p_vlm
);
119 vlc_object_t
*p_this
= VLC_OBJECT(libvlc
);
121 /* Avoid multiple creation */
122 vlc_mutex_lock( &vlm_mutex
);
126 { /* VLM already exists */
127 if( likely( p_vlm
->users
< UINT_MAX
) )
131 vlc_mutex_unlock( &vlm_mutex
);
135 msg_Dbg( p_this
, "creating VLM" );
137 p_vlm
= vlc_custom_create( p_this
->obj
.libvlc
, sizeof( *p_vlm
),
141 vlc_mutex_unlock( &vlm_mutex
);
145 vlc_mutex_init( &p_vlm
->lock
);
146 vlc_mutex_init( &p_vlm
->lock_manage
);
147 vlc_cond_init_daytime( &p_vlm
->wait_manage
);
149 p_vlm
->input_state_changed
= false;
151 TAB_INIT( p_vlm
->i_media
, p_vlm
->media
);
152 TAB_INIT( p_vlm
->i_schedule
, p_vlm
->schedule
);
154 var_Create( p_vlm
, "intf-event", VLC_VAR_ADDRESS
);
156 if( vlc_clone( &p_vlm
->thread
, Manage
, p_vlm
, VLC_THREAD_PRIORITY_LOW
) )
158 vlc_cond_destroy( &p_vlm
->wait_manage
);
159 vlc_mutex_destroy( &p_vlm
->lock
);
160 vlc_mutex_destroy( &p_vlm
->lock_manage
);
161 vlc_object_release( p_vlm
);
162 vlc_mutex_unlock( &vlm_mutex
);
166 *pp_vlm
= p_vlm
; /* for future reference */
168 vlc_mutex_unlock( &vlm_mutex
);
170 /* Load our configuration file */
171 if( psz_vlmconf
!= NULL
)
173 vlm_message_t
*p_message
= NULL
;
174 char *psz_buffer
= NULL
;
176 msg_Dbg( p_this
, "loading VLM configuration" );
177 if( asprintf(&psz_buffer
, "load %s", psz_vlmconf
) != -1 )
179 msg_Dbg( p_this
, "%s", psz_buffer
);
180 if( vlm_ExecuteCommand( p_vlm
, psz_buffer
, &p_message
) )
181 msg_Warn( p_this
, "error while loading the configuration file" );
183 vlm_MessageDelete( p_message
);
191 /*****************************************************************************
193 *****************************************************************************/
194 void vlm_Delete( vlm_t
*p_vlm
)
196 /* vlm_Delete() is serialized against itself, and against vlm_New().
197 * This mutex protects libvlc_priv->p_vlm and p_vlm->users. */
198 vlc_mutex_lock( &vlm_mutex
);
199 assert( p_vlm
->users
> 0 );
200 if( --p_vlm
->users
== 0 )
201 assert( libvlc_priv(p_vlm
->obj
.libvlc
)->p_vlm
== p_vlm
);
207 vlc_mutex_unlock( &vlm_mutex
);
211 /* Destroy and release VLM */
212 vlc_mutex_lock( &p_vlm
->lock
);
213 vlm_ControlInternal( p_vlm
, VLM_CLEAR_MEDIAS
);
214 TAB_CLEAN( p_vlm
->i_media
, p_vlm
->media
);
216 vlm_ControlInternal( p_vlm
, VLM_CLEAR_SCHEDULES
);
217 TAB_CLEAN( p_vlm
->i_schedule
, p_vlm
->schedule
);
218 vlc_mutex_unlock( &p_vlm
->lock
);
220 vlc_cancel( p_vlm
->thread
);
224 module_unneed( p_vlm
->p_vod
, p_vlm
->p_vod
->p_module
);
225 vlc_object_release( p_vlm
->p_vod
);
228 libvlc_priv(p_vlm
->obj
.libvlc
)->p_vlm
= NULL
;
229 vlc_mutex_unlock( &vlm_mutex
);
231 vlc_join( p_vlm
->thread
, NULL
);
233 vlc_cond_destroy( &p_vlm
->wait_manage
);
234 vlc_mutex_destroy( &p_vlm
->lock
);
235 vlc_mutex_destroy( &p_vlm
->lock_manage
);
236 vlc_object_release( p_vlm
);
239 /*****************************************************************************
240 * vlm_ExecuteCommand:
241 *****************************************************************************/
242 int vlm_ExecuteCommand( vlm_t
*p_vlm
, const char *psz_command
,
243 vlm_message_t
**pp_message
)
247 vlc_mutex_lock( &p_vlm
->lock
);
248 i_result
= ExecuteCommand( p_vlm
, psz_command
, pp_message
);
249 vlc_mutex_unlock( &p_vlm
->lock
);
254 /*****************************************************************************
256 *****************************************************************************/
257 static int vlm_MediaVodControl( void *p_private
, vod_media_t
*p_vod_media
,
258 const char *psz_id
, int i_query
, va_list args
)
260 vlm_t
*vlm
= (vlm_t
*)p_private
;
265 if( !p_private
|| !p_vod_media
)
268 vlc_mutex_lock( &vlm
->lock
);
271 for( i
= 0, id
= -1; i
< vlm
->i_media
; i
++ )
273 if( p_vod_media
== vlm
->media
[i
]->vod
.p_media
)
275 id
= vlm
->media
[i
]->cfg
.id
;
281 vlc_mutex_unlock( &vlm
->lock
);
289 psz
= (const char *)va_arg( args
, const char * );
290 int64_t *i_time
= (int64_t *)va_arg( args
, int64_t *);
291 bool b_retry
= false;
294 /* No start time requested: return the current NPT */
295 i_ret
= vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_TIME
, id
, psz_id
, i_time
);
296 /* The instance is not running yet, it will start at 0 */
302 /* We want to seek before unpausing, but it won't
303 * work if the instance is not running yet. */
304 b_retry
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_TIME
, id
, psz_id
, *i_time
);
307 i_ret
= vlm_ControlInternal( vlm
, VLM_START_MEDIA_VOD_INSTANCE
, id
, psz_id
, 0, psz
);
309 if (!i_ret
&& b_retry
)
310 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_TIME
, id
, psz_id
, *i_time
);
314 case VOD_MEDIA_PAUSE
:
316 int64_t *i_time
= (int64_t *)va_arg( args
, int64_t *);
317 i_ret
= vlm_ControlInternal( vlm
, VLM_PAUSE_MEDIA_INSTANCE
, id
, psz_id
);
319 i_ret
= vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_TIME
, id
, psz_id
, i_time
);
324 i_ret
= vlm_ControlInternal( vlm
, VLM_STOP_MEDIA_INSTANCE
, id
, psz_id
);
329 int64_t i_time
= (int64_t)va_arg( args
, int64_t );
330 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_TIME
, id
, psz_id
, i_time
);
334 case VOD_MEDIA_REWIND
:
336 double d_scale
= (double)va_arg( args
, double );
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
< 0.0 )
343 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, d_position
);
347 case VOD_MEDIA_FORWARD
:
349 double d_scale
= (double)va_arg( args
, double );
352 vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, &d_position
);
353 d_position
+= (d_scale
/ 1000.0);
354 if( d_position
> 1.0 )
356 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, d_position
);
361 i_ret
= VLC_EGENERIC
;
365 vlc_mutex_unlock( &vlm
->lock
);
371 /*****************************************************************************
373 *****************************************************************************/
374 static void* Manage( void* p_object
)
376 vlm_t
*vlm
= (vlm_t
*)p_object
;
377 time_t lastcheck
, now
, nextschedule
= 0;
383 char **ppsz_scheduled_commands
= NULL
;
384 int i_scheduled_commands
= 0;
385 bool scheduled_command
= false;
387 vlc_mutex_lock( &vlm
->lock_manage
);
388 mutex_cleanup_push( &vlm
->lock_manage
);
389 while( !vlm
->input_state_changed
&& !scheduled_command
)
391 if( nextschedule
!= 0 )
392 scheduled_command
= vlc_cond_timedwait_daytime( &vlm
->wait_manage
, &vlm
->lock_manage
, nextschedule
) != 0;
394 vlc_cond_wait( &vlm
->wait_manage
, &vlm
->lock_manage
);
396 vlm
->input_state_changed
= false;
398 vlc_mutex_unlock( &vlm
->lock_manage
);
400 int canc
= vlc_savecancel ();
401 /* destroy the inputs that wants to die, and launch the next input */
402 vlc_mutex_lock( &vlm
->lock
);
403 for( int i
= 0; i
< vlm
->i_media
; i
++ )
405 vlm_media_sys_t
*p_media
= vlm
->media
[i
];
407 for( int j
= 0; j
< p_media
->i_instance
; )
409 vlm_media_instance_sys_t
*p_instance
= p_media
->instance
[j
];
412 if( p_instance
->p_input
!= NULL
)
413 state
= var_GetInteger( p_instance
->p_input
, "state" );
414 if( state
== END_S
|| state
== ERROR_S
)
416 int i_new_input_index
;
419 i_new_input_index
= p_instance
->i_index
+ 1;
420 if( !p_media
->cfg
.b_vod
&& p_media
->cfg
.broadcast
.b_loop
&& i_new_input_index
>= p_media
->cfg
.i_input
)
421 i_new_input_index
= 0;
423 /* FIXME implement multiple input with VOD */
424 if( p_media
->cfg
.b_vod
|| i_new_input_index
>= p_media
->cfg
.i_input
)
425 vlm_ControlInternal( vlm
, VLM_STOP_MEDIA_INSTANCE
, p_media
->cfg
.id
, p_instance
->psz_name
);
427 vlm_ControlInternal( vlm
, VLM_START_MEDIA_BROADCAST_INSTANCE
, p_media
->cfg
.id
, p_instance
->psz_name
, i_new_input_index
);
442 for( int i
= 0; i
< vlm
->i_schedule
; i
++ )
444 time_t real_date
= vlm
->schedule
[i
]->date
;
446 if( vlm
->schedule
[i
]->b_enabled
)
449 if( vlm
->schedule
[i
]->date
== 0 ) // now !
451 vlm
->schedule
[i
]->date
= now
;
455 else if( vlm
->schedule
[i
]->period
!= 0 )
458 while( ((vlm
->schedule
[i
]->date
+ j
*
459 vlm
->schedule
[i
]->period
) <= lastcheck
) &&
460 ( vlm
->schedule
[i
]->i_repeat
> j
||
461 vlm
->schedule
[i
]->i_repeat
< 0 ) )
466 real_date
= vlm
->schedule
[i
]->date
+ j
*
467 vlm
->schedule
[i
]->period
;
470 if( real_date
<= now
)
472 if( real_date
> lastcheck
|| b_now
)
474 for( int j
= 0; j
< vlm
->schedule
[i
]->i_command
; j
++ )
476 TAB_APPEND( i_scheduled_commands
,
477 ppsz_scheduled_commands
,
478 strdup(vlm
->schedule
[i
]->command
[j
] ) );
482 else if( nextschedule
== 0 || real_date
< nextschedule
)
484 nextschedule
= real_date
;
489 while( i_scheduled_commands
)
491 vlm_message_t
*message
= NULL
;
492 char *psz_command
= ppsz_scheduled_commands
[0];
493 ExecuteCommand( vlm
, psz_command
,&message
);
495 /* for now, drop the message */
496 vlm_MessageDelete( message
);
497 TAB_REMOVE( i_scheduled_commands
,
498 ppsz_scheduled_commands
,
504 vlc_mutex_unlock( &vlm
->lock
);
505 vlc_restorecancel (canc
);
518 int i_connection_count;
519 int i_connection_active;
528 } vlm_media_status_t;
532 static vlm_media_sys_t
*vlm_ControlMediaGetById( vlm_t
*p_vlm
, int64_t id
)
534 for( int i
= 0; i
< p_vlm
->i_media
; i
++ )
536 if( p_vlm
->media
[i
]->cfg
.id
== id
)
537 return p_vlm
->media
[i
];
541 static vlm_media_sys_t
*vlm_ControlMediaGetByName( vlm_t
*p_vlm
, const char *psz_name
)
543 for( int i
= 0; i
< p_vlm
->i_media
; i
++ )
545 if( !strcmp( p_vlm
->media
[i
]->cfg
.psz_name
, psz_name
) )
546 return p_vlm
->media
[i
];
550 static int vlm_MediaDescriptionCheck( vlm_t
*p_vlm
, vlm_media_t
*p_cfg
)
552 if( !p_cfg
|| !p_cfg
->psz_name
||
553 !strcmp( p_cfg
->psz_name
, "all" ) || !strcmp( p_cfg
->psz_name
, "media" ) || !strcmp( p_cfg
->psz_name
, "schedule" ) )
556 for( int i
= 0; i
< p_vlm
->i_media
; i
++ )
558 if( p_vlm
->media
[i
]->cfg
.id
== p_cfg
->id
)
560 if( !strcmp( p_vlm
->media
[i
]->cfg
.psz_name
, p_cfg
->psz_name
) )
567 /* Called after a media description is changed/added */
568 static int vlm_OnMediaUpdate( vlm_t
*p_vlm
, vlm_media_sys_t
*p_media
)
570 vlm_media_t
*p_cfg
= &p_media
->cfg
;
571 /* Check if we need to create/delete a vod media */
572 if( p_cfg
->b_vod
&& p_vlm
->p_vod
)
574 if( !p_cfg
->b_enabled
&& p_media
->vod
.p_media
)
576 p_vlm
->p_vod
->pf_media_del( p_vlm
->p_vod
, p_media
->vod
.p_media
);
577 p_media
->vod
.p_media
= NULL
;
579 else if( p_cfg
->b_enabled
&& !p_media
->vod
.p_media
&& p_cfg
->i_input
)
581 /* Pre-parse the input */
582 input_thread_t
*p_input
;
587 input_item_Release( p_media
->vod
.p_item
);
589 if( strstr( p_cfg
->ppsz_input
[0], "://" ) == NULL
)
591 char *psz_uri
= vlc_path2uri( p_cfg
->ppsz_input
[0], NULL
);
592 p_media
->vod
.p_item
= input_item_New( psz_uri
,
597 p_media
->vod
.p_item
= input_item_New( p_cfg
->ppsz_input
[0],
600 if( p_cfg
->psz_output
)
602 if( asprintf( &psz_output
, "%s:description", p_cfg
->psz_output
) == -1 )
606 psz_output
= strdup( "#description" );
608 if( psz_output
&& asprintf( &psz_dup
, "sout=%s", psz_output
) != -1 )
610 input_item_AddOption( p_media
->vod
.p_item
, psz_dup
, VLC_INPUT_OPTION_TRUSTED
);
615 for( int i
= 0; i
< p_cfg
->i_option
; i
++ )
616 input_item_AddOption( p_media
->vod
.p_item
,
617 p_cfg
->ppsz_option
[i
], VLC_INPUT_OPTION_TRUSTED
);
619 if( asprintf( &psz_header
, _("Media: %s"), p_cfg
->psz_name
) == -1 )
622 sout_description_data_t data
;
623 TAB_INIT(data
.i_es
, data
.es
);
625 p_input
= input_Create( p_vlm
->p_vod
, input_LegacyEvents
, NULL
,
626 p_media
->vod
.p_item
, psz_header
, NULL
, NULL
);
629 vlc_sem_t sem_preparse
;
630 vlc_sem_init( &sem_preparse
, 0 );
632 preparse_data_t preparse
= { .p_sem
= &sem_preparse
,
633 .b_mux
= (p_cfg
->vod
.psz_mux
!= NULL
) };
634 input_LegacyVarInit( p_input
);
635 var_AddCallback( p_input
, "intf-event", InputEventPreparse
,
638 data
.sem
= &sem_preparse
;
639 var_Create( p_input
, "sout-description-data", VLC_VAR_ADDRESS
);
640 var_SetAddress( p_input
, "sout-description-data", &data
);
642 if( !input_Start( p_input
) )
643 vlc_sem_wait( &sem_preparse
);
645 var_DelCallback( p_input
, "intf-event", InputEventPreparse
,
648 input_Stop( p_input
);
649 input_Close( p_input
);
650 vlc_sem_destroy( &sem_preparse
);
654 /* XXX: Don't do it that way, but properly use a new input item ref. */
655 input_item_t item
= *p_media
->vod
.p_item
;;
656 es_format_t es
, *p_es
= &es
;
657 if( p_cfg
->vod
.psz_mux
)
660 if (!strcmp(p_cfg
->vod
.psz_mux
, "ps"))
662 else if (!strcmp(p_cfg
->vod
.psz_mux
, "ts"))
665 psz_mux
= p_cfg
->vod
.psz_mux
;
669 unsigned char utext
[5];
673 sprintf( fourcc
.text
, "%4.4s", psz_mux
);
674 for( int i
= 0; i
< 4; i
++ )
675 fourcc
.utext
[i
] = tolower(fourcc
.utext
[i
]);
679 es_format_Init( &es
, VIDEO_ES
, fourcc
.value
);
683 item
.i_es
= data
.i_es
;
686 p_media
->vod
.p_media
= p_vlm
->p_vod
->pf_media_new( p_vlm
->p_vod
,
687 p_cfg
->psz_name
, &item
);
689 TAB_CLEAN(data
.i_es
, data
.es
);
692 else if ( p_cfg
->b_vod
)
693 msg_Err( p_vlm
, "vod server is not loaded" );
696 /* TODO start media if needed */
699 /* TODO add support of var vlm_media_broadcast/vlm_media_vod */
701 vlm_SendEventMediaChanged( p_vlm
, p_cfg
->id
, p_cfg
->psz_name
);
704 static int vlm_ControlMediaChange( vlm_t
*p_vlm
, vlm_media_t
*p_cfg
)
706 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, p_cfg
->id
);
709 if( !p_media
|| vlm_MediaDescriptionCheck( p_vlm
, p_cfg
) )
711 if( ( p_media
->cfg
.b_vod
&& !p_cfg
->b_vod
) || ( !p_media
->cfg
.b_vod
&& p_cfg
->b_vod
) )
716 /* TODO check what are the changes being done (stop instance if needed) */
719 vlm_media_Clean( &p_media
->cfg
);
720 vlm_media_Copy( &p_media
->cfg
, p_cfg
);
722 return vlm_OnMediaUpdate( p_vlm
, p_media
);
725 static int vlm_ControlMediaAdd( vlm_t
*p_vlm
, vlm_media_t
*p_cfg
, int64_t *p_id
)
727 vlm_media_sys_t
*p_media
;
729 if( vlm_MediaDescriptionCheck( p_vlm
, p_cfg
) || vlm_ControlMediaGetByName( p_vlm
, p_cfg
->psz_name
) )
731 msg_Err( p_vlm
, "invalid media description" );
734 /* Check if we need to load the VOD server */
735 if( p_cfg
->b_vod
&& !p_vlm
->p_vod
)
737 p_vlm
->p_vod
= vlc_custom_create( VLC_OBJECT(p_vlm
), sizeof( vod_t
),
739 p_vlm
->p_vod
->p_module
= module_need_var( p_vlm
->p_vod
, "vod server", "vod-server" );
740 if( !p_vlm
->p_vod
->p_module
)
742 msg_Err( p_vlm
, "cannot find vod server" );
743 vlc_object_release( p_vlm
->p_vod
);
748 p_vlm
->p_vod
->p_data
= p_vlm
;
749 p_vlm
->p_vod
->pf_media_control
= vlm_MediaVodControl
;
752 p_media
= calloc( 1, sizeof( vlm_media_sys_t
) );
756 vlm_media_Copy( &p_media
->cfg
, p_cfg
);
757 p_media
->cfg
.id
= p_vlm
->i_id
++;
758 /* FIXME do we do something here if enabled is true ? */
760 p_media
->vod
.p_item
= input_item_New( NULL
, NULL
);
762 p_media
->vod
.p_media
= NULL
;
763 TAB_INIT( p_media
->i_instance
, p_media
->instance
);
766 TAB_APPEND( p_vlm
->i_media
, p_vlm
->media
, p_media
);
769 *p_id
= p_media
->cfg
.id
;
772 vlm_SendEventMediaAdded( p_vlm
, p_media
->cfg
.id
, p_media
->cfg
.psz_name
);
773 return vlm_OnMediaUpdate( p_vlm
, p_media
);
776 static int vlm_ControlMediaDel( vlm_t
*p_vlm
, int64_t id
)
778 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
783 while( p_media
->i_instance
> 0 )
784 vlm_ControlInternal( p_vlm
, VLM_STOP_MEDIA_INSTANCE
, id
, p_media
->instance
[0]->psz_name
);
786 if( p_media
->cfg
.b_vod
)
788 p_media
->cfg
.b_enabled
= false;
789 vlm_OnMediaUpdate( p_vlm
, p_media
);
793 vlm_SendEventMediaRemoved( p_vlm
, id
, p_media
->cfg
.psz_name
);
795 vlm_media_Clean( &p_media
->cfg
);
797 input_item_Release( p_media
->vod
.p_item
);
799 if( p_media
->vod
.p_media
)
800 p_vlm
->p_vod
->pf_media_del( p_vlm
->p_vod
, p_media
->vod
.p_media
);
802 TAB_REMOVE( p_vlm
->i_media
, p_vlm
->media
, p_media
);
808 static int vlm_ControlMediaGets( vlm_t
*p_vlm
, vlm_media_t
***ppp_dsc
, int *pi_dsc
)
810 vlm_media_t
**pp_dsc
;
813 TAB_INIT( i_dsc
, pp_dsc
);
814 for( int i
= 0; i
< p_vlm
->i_media
; i
++ )
816 vlm_media_t
*p_dsc
= vlm_media_Duplicate( &p_vlm
->media
[i
]->cfg
);
817 TAB_APPEND( i_dsc
, pp_dsc
, p_dsc
);
825 static int vlm_ControlMediaClear( vlm_t
*p_vlm
)
827 while( p_vlm
->i_media
> 0 )
828 vlm_ControlMediaDel( p_vlm
, p_vlm
->media
[0]->cfg
.id
);
832 static int vlm_ControlMediaGet( vlm_t
*p_vlm
, int64_t id
, vlm_media_t
**pp_dsc
)
834 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
838 *pp_dsc
= vlm_media_Duplicate( &p_media
->cfg
);
841 static int vlm_ControlMediaGetId( vlm_t
*p_vlm
, const char *psz_name
, int64_t *p_id
)
843 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetByName( p_vlm
, psz_name
);
847 *p_id
= p_media
->cfg
.id
;
851 static vlm_media_instance_sys_t
*vlm_ControlMediaInstanceGetByName( vlm_media_sys_t
*p_media
, const char *psz_id
)
853 for( int i
= 0; i
< p_media
->i_instance
; i
++ )
855 const char *psz
= p_media
->instance
[i
]->psz_name
;
856 if( ( psz
== NULL
&& psz_id
== NULL
) ||
857 ( psz
&& psz_id
&& !strcmp( psz
, psz_id
) ) )
858 return p_media
->instance
[i
];
862 static vlm_media_instance_sys_t
*vlm_MediaInstanceNew( vlm_t
*p_vlm
, const char *psz_name
)
864 vlm_media_instance_sys_t
*p_instance
= calloc( 1, sizeof(vlm_media_instance_sys_t
) );
868 p_instance
->psz_name
= NULL
;
870 p_instance
->psz_name
= strdup( psz_name
);
872 p_instance
->p_item
= input_item_New( NULL
, NULL
);
874 p_instance
->i_index
= 0;
875 p_instance
->b_sout_keep
= false;
876 p_instance
->p_parent
= vlc_object_create( p_vlm
, sizeof (vlc_object_t
) );
877 p_instance
->p_input
= NULL
;
878 p_instance
->p_input_resource
= input_resource_New( p_instance
->p_parent
);
882 static void vlm_MediaInstanceDelete( vlm_t
*p_vlm
, int64_t id
, vlm_media_instance_sys_t
*p_instance
, vlm_media_sys_t
*p_media
)
884 input_thread_t
*p_input
= p_instance
->p_input
;
887 input_Stop( p_input
);
888 input_Close( p_input
);
890 vlm_SendEventMediaInstanceStopped( p_vlm
, id
, p_media
->cfg
.psz_name
);
892 input_resource_Terminate( p_instance
->p_input_resource
);
893 input_resource_Release( p_instance
->p_input_resource
);
894 vlc_object_release( p_instance
->p_parent
);
896 TAB_REMOVE( p_media
->i_instance
, p_media
->instance
, p_instance
);
897 input_item_Release( p_instance
->p_item
);
898 free( p_instance
->psz_name
);
903 static int vlm_ControlMediaInstanceStart( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
, int i_input_index
, const char *psz_vod_output
)
905 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
906 vlm_media_instance_sys_t
*p_instance
;
909 if( !p_media
|| !p_media
->cfg
.b_enabled
|| p_media
->cfg
.i_input
<= 0 )
912 /* TODO support multiple input for VOD with sout-keep ? */
914 if( ( p_media
->cfg
.b_vod
&& !psz_vod_output
) || ( !p_media
->cfg
.b_vod
&& psz_vod_output
) )
917 if( i_input_index
< 0 || i_input_index
>= p_media
->cfg
.i_input
)
920 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
923 vlm_media_t
*p_cfg
= &p_media
->cfg
;
925 p_instance
= vlm_MediaInstanceNew( p_vlm
, psz_id
);
931 var_Create( p_instance
->p_parent
, "vod-media", VLC_VAR_ADDRESS
);
932 var_SetAddress( p_instance
->p_parent
, "vod-media",
933 p_media
->vod
.p_media
);
934 var_Create( p_instance
->p_parent
, "vod-session", VLC_VAR_STRING
);
935 var_SetString( p_instance
->p_parent
, "vod-session", psz_id
);
938 if( p_cfg
->psz_output
!= NULL
|| psz_vod_output
!= NULL
)
941 if( asprintf( &psz_buffer
, "sout=%s%s%s",
942 p_cfg
->psz_output
? p_cfg
->psz_output
: "",
943 (p_cfg
->psz_output
&& psz_vod_output
) ? ":" : psz_vod_output
? "#" : "",
944 psz_vod_output
? psz_vod_output
: "" ) != -1 )
946 input_item_AddOption( p_instance
->p_item
, psz_buffer
, VLC_INPUT_OPTION_TRUSTED
);
951 for( int i
= 0; i
< p_cfg
->i_option
; i
++ )
953 if( !strcmp( p_cfg
->ppsz_option
[i
], "sout-keep" ) )
954 p_instance
->b_sout_keep
= true;
955 else if( !strcmp( p_cfg
->ppsz_option
[i
], "nosout-keep" ) || !strcmp( p_cfg
->ppsz_option
[i
], "no-sout-keep" ) )
956 p_instance
->b_sout_keep
= false;
958 input_item_AddOption( p_instance
->p_item
, p_cfg
->ppsz_option
[i
], VLC_INPUT_OPTION_TRUSTED
);
960 TAB_APPEND( p_media
->i_instance
, p_media
->instance
, p_instance
);
963 /* Stop old instance */
964 input_thread_t
*p_input
= p_instance
->p_input
;
967 if( p_instance
->i_index
== i_input_index
)
969 int state
= var_GetInteger( p_input
, "state" );
970 if( state
== PAUSE_S
)
971 var_SetInteger( p_input
, "state", PLAYING_S
);
975 input_Stop( p_input
);
976 input_Close( p_input
);
978 if( !p_instance
->b_sout_keep
)
979 input_resource_TerminateSout( p_instance
->p_input_resource
);
980 input_resource_TerminateVout( p_instance
->p_input_resource
);
982 vlm_SendEventMediaInstanceStopped( p_vlm
, id
, p_media
->cfg
.psz_name
);
986 p_instance
->i_index
= i_input_index
;
987 if( strstr( p_media
->cfg
.ppsz_input
[p_instance
->i_index
], "://" ) == NULL
)
989 char *psz_uri
= vlc_path2uri(
990 p_media
->cfg
.ppsz_input
[p_instance
->i_index
], NULL
);
991 input_item_SetURI( p_instance
->p_item
, psz_uri
) ;
995 input_item_SetURI( p_instance
->p_item
, p_media
->cfg
.ppsz_input
[p_instance
->i_index
] ) ;
997 if( asprintf( &psz_log
, _("Media: %s"), p_media
->cfg
.psz_name
) != -1 )
999 p_instance
->p_input
= input_Create( p_instance
->p_parent
,
1000 input_LegacyEvents
, NULL
,
1001 p_instance
->p_item
, psz_log
,
1002 p_instance
->p_input_resource
,
1004 if( p_instance
->p_input
)
1006 input_LegacyVarInit( p_instance
->p_input
);
1007 var_AddCallback( p_instance
->p_input
, "intf-event", InputEvent
, p_media
);
1009 if( input_Start( p_instance
->p_input
) != VLC_SUCCESS
)
1011 var_DelCallback( p_instance
->p_input
, "intf-event", InputEvent
, p_media
);
1012 input_Close( p_instance
->p_input
);
1013 p_instance
->p_input
= NULL
;
1017 if( !p_instance
->p_input
)
1019 vlm_MediaInstanceDelete( p_vlm
, id
, p_instance
, p_media
);
1023 vlm_SendEventMediaInstanceStarted( p_vlm
, id
, p_media
->cfg
.psz_name
);
1031 static int vlm_ControlMediaInstanceStop( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
)
1033 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1034 vlm_media_instance_sys_t
*p_instance
;
1037 return VLC_EGENERIC
;
1039 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
1041 return VLC_EGENERIC
;
1043 vlm_MediaInstanceDelete( p_vlm
, id
, p_instance
, p_media
);
1047 static int vlm_ControlMediaInstancePause( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
)
1049 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1050 vlm_media_instance_sys_t
*p_instance
;
1054 return VLC_EGENERIC
;
1056 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
1057 if( !p_instance
|| !p_instance
->p_input
)
1058 return VLC_EGENERIC
;
1060 /* Toggle pause state */
1061 i_state
= var_GetInteger( p_instance
->p_input
, "state" );
1062 if( i_state
== PAUSE_S
&& !p_media
->cfg
.b_vod
)
1063 var_SetInteger( p_instance
->p_input
, "state", PLAYING_S
);
1064 else if( i_state
== PLAYING_S
)
1065 var_SetInteger( p_instance
->p_input
, "state", PAUSE_S
);
1068 static int vlm_ControlMediaInstanceGetTimePosition( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
, int64_t *pi_time
, double *pd_position
)
1070 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1071 vlm_media_instance_sys_t
*p_instance
;
1074 return VLC_EGENERIC
;
1076 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
1077 if( !p_instance
|| !p_instance
->p_input
)
1078 return VLC_EGENERIC
;
1081 *pi_time
= US_FROM_VLC_TICK(var_GetInteger( p_instance
->p_input
, "time" ));
1083 *pd_position
= var_GetFloat( p_instance
->p_input
, "position" );
1086 static int vlm_ControlMediaInstanceSetTimePosition( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
, int64_t i_time
, double d_position
)
1088 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1089 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
;
1099 return var_SetInteger( p_instance
->p_input
, "time", VLC_TICK_FROM_US(i_time
) );
1100 else if( d_position
>= 0 && d_position
<= 100 )
1101 return var_SetFloat( p_instance
->p_input
, "position", d_position
);
1102 return VLC_EGENERIC
;
1105 static int vlm_ControlMediaInstanceGets( vlm_t
*p_vlm
, int64_t id
, vlm_media_instance_t
***ppp_idsc
, int *pi_instance
)
1107 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1108 vlm_media_instance_t
**pp_idsc
;
1112 return VLC_EGENERIC
;
1114 TAB_INIT( i_idsc
, pp_idsc
);
1115 for( int i
= 0; i
< p_media
->i_instance
; i
++ )
1117 vlm_media_instance_sys_t
*p_instance
= p_media
->instance
[i
];
1118 vlm_media_instance_t
*p_idsc
= vlm_media_instance_New();
1120 if( p_instance
->psz_name
)
1121 p_idsc
->psz_name
= strdup( p_instance
->psz_name
);
1122 if( p_instance
->p_input
)
1124 p_idsc
->i_time
= US_FROM_VLC_TICK(var_GetInteger( p_instance
->p_input
, "time" ));
1125 p_idsc
->i_length
= US_FROM_VLC_TICK(var_GetInteger( p_instance
->p_input
, "length" ));
1126 p_idsc
->d_position
= var_GetFloat( p_instance
->p_input
, "position" );
1127 if( var_GetInteger( p_instance
->p_input
, "state" ) == PAUSE_S
)
1128 p_idsc
->b_paused
= true;
1129 p_idsc
->i_rate
= INPUT_RATE_DEFAULT
1130 / var_GetFloat( p_instance
->p_input
, "rate" );
1133 TAB_APPEND( i_idsc
, pp_idsc
, p_idsc
);
1135 *ppp_idsc
= pp_idsc
;
1136 *pi_instance
= i_idsc
;
1140 static int vlm_ControlMediaInstanceClear( vlm_t
*p_vlm
, int64_t id
)
1142 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
1145 return VLC_EGENERIC
;
1147 while( p_media
->i_instance
> 0 )
1148 vlm_ControlMediaInstanceStop( p_vlm
, id
, p_media
->instance
[0]->psz_name
);
1153 static int vlm_ControlScheduleClear( vlm_t
*p_vlm
)
1155 while( p_vlm
->i_schedule
> 0 )
1156 vlm_ScheduleDelete( p_vlm
, p_vlm
->schedule
[0] );
1161 static int vlm_vaControlInternal( vlm_t
*p_vlm
, int i_query
, va_list args
)
1164 vlm_media_t
**pp_dsc
;
1165 vlm_media_t
***ppp_dsc
;
1166 vlm_media_instance_t
***ppp_idsc
;
1168 const char *psz_vod
;
1182 case VLM_GET_MEDIAS
:
1183 ppp_dsc
= (vlm_media_t
***)va_arg( args
, vlm_media_t
*** );
1184 pi_int
= (int *)va_arg( args
, int * );
1185 return vlm_ControlMediaGets( p_vlm
, ppp_dsc
, pi_int
);
1187 case VLM_CLEAR_MEDIAS
:
1188 return vlm_ControlMediaClear( p_vlm
);
1190 case VLM_CHANGE_MEDIA
:
1191 p_dsc
= (vlm_media_t
*)va_arg( args
, vlm_media_t
* );
1192 return vlm_ControlMediaChange( p_vlm
, p_dsc
);
1195 p_dsc
= (vlm_media_t
*)va_arg( args
, vlm_media_t
* );
1196 p_id
= (int64_t*)va_arg( args
, int64_t * );
1197 return vlm_ControlMediaAdd( p_vlm
, p_dsc
, p_id
);
1200 id
= (int64_t)va_arg( args
, int64_t );
1201 return vlm_ControlMediaDel( p_vlm
, id
);
1204 id
= (int64_t)va_arg( args
, int64_t );
1205 pp_dsc
= (vlm_media_t
**)va_arg( args
, vlm_media_t
** );
1206 return vlm_ControlMediaGet( p_vlm
, id
, pp_dsc
);
1208 case VLM_GET_MEDIA_ID
:
1209 psz_id
= (const char*)va_arg( args
, const char * );
1210 p_id
= (int64_t*)va_arg( args
, int64_t * );
1211 return vlm_ControlMediaGetId( p_vlm
, psz_id
, p_id
);
1214 /* Media instance control */
1215 case VLM_GET_MEDIA_INSTANCES
:
1216 id
= (int64_t)va_arg( args
, int64_t );
1217 ppp_idsc
= (vlm_media_instance_t
***)va_arg( args
, vlm_media_instance_t
*** );
1218 pi_int
= (int *)va_arg( args
, int *);
1219 return vlm_ControlMediaInstanceGets( p_vlm
, id
, ppp_idsc
, pi_int
);
1221 case VLM_CLEAR_MEDIA_INSTANCES
:
1222 id
= (int64_t)va_arg( args
, int64_t );
1223 return vlm_ControlMediaInstanceClear( p_vlm
, id
);
1226 case VLM_START_MEDIA_BROADCAST_INSTANCE
:
1227 id
= (int64_t)va_arg( args
, int64_t );
1228 psz_id
= (const char*)va_arg( args
, const char* );
1229 i_int
= (int)va_arg( args
, int );
1230 return vlm_ControlMediaInstanceStart( p_vlm
, id
, psz_id
, i_int
, NULL
);
1232 case VLM_START_MEDIA_VOD_INSTANCE
:
1233 id
= (int64_t)va_arg( args
, int64_t );
1234 psz_id
= (const char*)va_arg( args
, const char* );
1235 i_int
= (int)va_arg( args
, int );
1236 psz_vod
= (const char*)va_arg( args
, const char* );
1238 return VLC_EGENERIC
;
1239 return vlm_ControlMediaInstanceStart( p_vlm
, id
, psz_id
, i_int
, psz_vod
);
1241 case VLM_STOP_MEDIA_INSTANCE
:
1242 id
= (int64_t)va_arg( args
, int64_t );
1243 psz_id
= (const char*)va_arg( args
, const char* );
1244 return vlm_ControlMediaInstanceStop( p_vlm
, id
, psz_id
);
1246 case VLM_PAUSE_MEDIA_INSTANCE
:
1247 id
= (int64_t)va_arg( args
, int64_t );
1248 psz_id
= (const char*)va_arg( args
, const char* );
1249 return vlm_ControlMediaInstancePause( p_vlm
, id
, psz_id
);
1251 case VLM_GET_MEDIA_INSTANCE_TIME
:
1252 id
= (int64_t)va_arg( args
, int64_t );
1253 psz_id
= (const char*)va_arg( args
, const char* );
1254 pi_i64
= (int64_t*)va_arg( args
, int64_t * );
1255 return vlm_ControlMediaInstanceGetTimePosition( p_vlm
, id
, psz_id
, pi_i64
, NULL
);
1256 case VLM_GET_MEDIA_INSTANCE_POSITION
:
1257 id
= (int64_t)va_arg( args
, int64_t );
1258 psz_id
= (const char*)va_arg( args
, const char* );
1259 pd_double
= (double*)va_arg( args
, double* );
1260 return vlm_ControlMediaInstanceGetTimePosition( p_vlm
, id
, psz_id
, NULL
, pd_double
);
1262 case VLM_SET_MEDIA_INSTANCE_TIME
:
1263 id
= (int64_t)va_arg( args
, int64_t );
1264 psz_id
= (const char*)va_arg( args
, const char* );
1265 i_i64
= (int64_t)va_arg( args
, int64_t);
1266 return vlm_ControlMediaInstanceSetTimePosition( p_vlm
, id
, psz_id
, i_i64
, -1 );
1267 case VLM_SET_MEDIA_INSTANCE_POSITION
:
1268 id
= (int64_t)va_arg( args
, int64_t );
1269 psz_id
= (const char*)va_arg( args
, const char* );
1270 d_double
= (double)va_arg( args
, double );
1271 return vlm_ControlMediaInstanceSetTimePosition( p_vlm
, id
, psz_id
, -1, d_double
);
1273 case VLM_CLEAR_SCHEDULES
:
1274 return vlm_ControlScheduleClear( p_vlm
);
1277 msg_Err( p_vlm
, "unknown VLM query" );
1278 return VLC_EGENERIC
;
1282 int vlm_ControlInternal( vlm_t
*p_vlm
, int i_query
, ... )
1287 va_start( args
, i_query
);
1288 i_result
= vlm_vaControlInternal( p_vlm
, i_query
, args
);
1294 int vlm_Control( vlm_t
*p_vlm
, int i_query
, ... )
1299 va_start( args
, i_query
);
1301 vlc_mutex_lock( &p_vlm
->lock
);
1302 i_result
= vlm_vaControlInternal( p_vlm
, i_query
, args
);
1303 vlc_mutex_unlock( &p_vlm
->lock
);