1 /*****************************************************************************
2 * vlm.c: VLM interface plugin
3 *****************************************************************************
4 * Copyright (C) 2000-2005 the VideoLAN team
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
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
36 #include <ctype.h> /* tolower() */
44 # include <sys/time.h> /* gettimeofday() */
48 # include <time.h> /* ctime() */
49 # include <sys/timeb.h> /* ftime() */
52 #include <vlc_input.h>
53 #include "input_internal.h"
54 #include <vlc_stream.h>
55 #include "vlm_internal.h"
57 #include <vlc_charset.h>
59 #include "../stream_output/stream_output.h"
61 /*****************************************************************************
63 *****************************************************************************/
65 /* ugly kludge to avoid "null format string" warnings,
66 * even if we handle NULL format string in vlm_MessageNew() */
67 static const char *vlm_NULL
= NULL
;
70 static int vlm_ControlInternal( vlm_t
*, int, ... );
73 static vlm_message_t
*vlm_Show( vlm_t
*, vlm_media_sys_t
*, vlm_schedule_sys_t
*, const char * );
75 static vlm_schedule_sys_t
*vlm_ScheduleSearch( vlm_t
*, const char * );
77 static char *Save( vlm_t
* );
78 static int Load( vlm_t
*, char * );
80 static int ExecuteCommand( vlm_t
*, const char *, vlm_message_t
** );
82 static int Manage( vlc_object_t
* );
84 static vlm_schedule_sys_t
*vlm_ScheduleNew( vlm_t
*vlm
, const char *psz_name
);
85 static void vlm_ScheduleDelete( vlm_t
*vlm
, vlm_schedule_sys_t
*sched
);
86 static int vlm_ScheduleSetup( vlm_schedule_sys_t
*schedule
, const char *psz_cmd
,
87 const char *psz_value
);
89 static int vlm_MediaVodControl( void *, vod_media_t
*, const char *, int, va_list );
92 static vlm_media_sys_t
*vlm_MediaSearch( vlm_t
*, const char *);
94 /*****************************************************************************
96 *****************************************************************************/
97 vlm_t
*__vlm_New ( vlc_object_t
*p_this
)
103 /* Avoid multiple creation */
104 if( var_Create( p_this
->p_libvlc
, "vlm_mutex", VLC_VAR_MUTEX
) ||
105 var_Get( p_this
->p_libvlc
, "vlm_mutex", &lockval
) )
108 vlc_mutex_lock( lockval
.p_address
);
110 p_vlm
= vlc_object_find( p_this
, VLC_OBJECT_VLM
, FIND_ANYWHERE
);
113 vlc_object_yield( p_vlm
);
114 vlc_mutex_unlock( lockval
.p_address
);
118 msg_Dbg( p_this
, "creating VLM" );
120 p_vlm
= vlc_object_create( p_this
, VLC_OBJECT_VLM
);
123 vlc_mutex_unlock( lockval
.p_address
);
127 vlc_mutex_init( p_this
->p_libvlc
, &p_vlm
->lock
);
129 TAB_INIT( p_vlm
->i_media
, p_vlm
->media
);
130 TAB_INIT( p_vlm
->i_schedule
, p_vlm
->schedule
);
133 vlc_object_yield( p_vlm
);
134 vlc_object_attach( p_vlm
, p_this
->p_libvlc
);
136 if( vlc_thread_create( p_vlm
, "vlm thread",
137 Manage
, VLC_THREAD_PRIORITY_LOW
, VLC_FALSE
) )
139 vlc_mutex_destroy( &p_vlm
->lock
);
140 vlc_object_release( p_vlm
);
144 /* Load our configuration file */
145 psz_vlmconf
= var_CreateGetString( p_vlm
, "vlm-conf" );
146 if( psz_vlmconf
&& *psz_vlmconf
)
148 vlm_message_t
*p_message
= NULL
;
149 char *psz_buffer
= NULL
;
151 msg_Dbg( p_this
, "loading VLM configuration" );
152 asprintf(&psz_buffer
, "load %s", psz_vlmconf
);
155 msg_Dbg( p_this
, psz_buffer
);
156 if( vlm_ExecuteCommand( p_vlm
, psz_buffer
, &p_message
) )
157 msg_Warn( p_this
, "error while loading the configuration file" );
159 vlm_MessageDelete(p_message
);
165 vlc_mutex_unlock( lockval
.p_address
);
170 /*****************************************************************************
172 *****************************************************************************/
173 void vlm_Delete( vlm_t
*p_vlm
)
177 var_Get( p_vlm
->p_libvlc
, "vlm_mutex", &lockval
);
178 vlc_mutex_lock( lockval
.p_address
);
180 vlc_object_release( p_vlm
);
182 if( p_vlm
->p_internals
->i_refcount
> 0 )
184 vlc_mutex_unlock( lockval
.p_address
);
188 vlc_object_kill( p_vlm
);
189 vlc_thread_join( p_vlm
);
191 vlc_object_detach( p_vlm
);
193 vlm_ControlInternal( p_vlm
, VLM_CLEAR_MEDIAS
);
194 TAB_CLEAN( p_vlm
->i_media
, p_vlm
->media
);
196 vlm_ControlInternal( p_vlm
, VLM_CLEAR_SCHEDULES
);
197 TAB_CLEAN( p_vlm
->schedule
, p_vlm
->schedule
);
199 vlc_mutex_destroy( &p_vlm
->lock
);
201 vlc_object_release( p_vlm
);
202 vlc_mutex_unlock( lockval
.p_address
);
205 /*****************************************************************************
206 * vlm_ExecuteCommand:
207 *****************************************************************************/
208 int vlm_ExecuteCommand( vlm_t
*p_vlm
, const char *psz_command
,
209 vlm_message_t
**pp_message
)
213 vlc_mutex_lock( &p_vlm
->lock
);
214 i_result
= ExecuteCommand( p_vlm
, psz_command
, pp_message
);
215 vlc_mutex_unlock( &p_vlm
->lock
);
221 static const char quotes
[] = "\"'";
223 * FindCommandEnd: look for the end of a possibly quoted string
224 * @return NULL on mal-formatted string,
225 * pointer past the last character otherwise.
227 static const char *FindCommandEnd( const char *psz_sent
)
231 while( (c
= *psz_sent
) != '\0' )
235 if( strchr(quotes
,c
) ) // opening quote
237 else if( isspace(c
) ) // non-escaped space
241 psz_sent
++; // skip escaped character
242 if( *psz_sent
== '\0' )
248 if( c
== quote
) // non-escaped matching quote
250 else if( (quote
== '"') && (c
== '\\') )
252 psz_sent
++; // skip escaped character
253 if (*psz_sent
== '\0')
254 return NULL
; // error, closing quote missing
260 // error (NULL) if we could not find a matching quote
261 return quote
? NULL
: psz_sent
;
266 * Unescape a nul-terminated string.
267 * Note that in and out can be identical.
269 * @param out output buffer (at least <strlen (in) + 1> characters long)
270 * @param in nul-terminated string to be unescaped
272 * @return 0 on success, -1 on error.
274 static int Unescape( char *out
, const char *in
)
278 while( (c
= *in
++) != '\0' )
282 if (strchr(quotes
,c
)) // opening quote
306 /* None of the special cases - copy the backslash */
312 if( c
== quote
) // non-escaped matching quote
317 if( (quote
== '"') && (c
== '\\') )
326 case '\0': // should never happen
330 /* None of the special cases - copy the backslash */
342 /*****************************************************************************
343 * ExecuteCommand: The main state machine
344 *****************************************************************************
345 * Execute a command which ends with '\0' (string)
346 *****************************************************************************/
347 static int ExecuteSyntaxError( const char *psz_cmd
, vlm_message_t
**pp_status
)
349 *pp_status
= vlm_MessageNew( psz_cmd
, "Wrong command syntax" );
353 static vlc_bool_t
ExecuteIsMedia( vlm_t
*p_vlm
, const char *psz_name
)
357 if( !psz_name
|| vlm_ControlInternal( p_vlm
, VLM_GET_MEDIA_ID
, psz_name
, &id
) )
361 static vlc_bool_t
ExecuteIsSchedule( vlm_t
*p_vlm
, const char *psz_name
)
363 if( !psz_name
|| !vlm_ScheduleSearch( p_vlm
, psz_name
) )
368 static int ExecuteDel( vlm_t
*p_vlm
, const char *psz_name
, vlm_message_t
**pp_status
)
370 vlm_media_sys_t
*p_media
;
371 vlm_schedule_sys_t
*p_schedule
;
373 p_media
= vlm_MediaSearch( p_vlm
, psz_name
);
374 p_schedule
= vlm_ScheduleSearch( p_vlm
, psz_name
);
376 if( p_schedule
!= NULL
)
378 vlm_ScheduleDelete( p_vlm
, p_schedule
);
380 else if( p_media
!= NULL
)
382 vlm_ControlInternal( p_vlm
, VLM_DEL_MEDIA
, p_media
->cfg
.id
);
384 else if( !strcmp(psz_name
, "media") )
386 vlm_ControlInternal( p_vlm
, VLM_CLEAR_MEDIAS
);
388 else if( !strcmp(psz_name
, "schedule") )
390 vlm_ControlInternal( p_vlm
, VLM_CLEAR_SCHEDULES
);
392 else if( !strcmp(psz_name
, "all") )
394 vlm_ControlInternal( p_vlm
, VLM_CLEAR_MEDIAS
);
395 vlm_ControlInternal( p_vlm
, VLM_CLEAR_SCHEDULES
);
399 *pp_status
= vlm_MessageNew( "del", "%s: media unknown", psz_name
);
403 *pp_status
= vlm_MessageNew( "del", vlm_NULL
);
407 static int ExecuteShow( vlm_t
*p_vlm
, const char *psz_name
, vlm_message_t
**pp_status
)
409 vlm_media_sys_t
*p_media
;
410 vlm_schedule_sys_t
*p_schedule
;
414 *pp_status
= vlm_Show( p_vlm
, NULL
, NULL
, NULL
);
418 p_media
= vlm_MediaSearch( p_vlm
, psz_name
);
419 p_schedule
= vlm_ScheduleSearch( p_vlm
, psz_name
);
421 if( p_schedule
!= NULL
)
422 *pp_status
= vlm_Show( p_vlm
, NULL
, p_schedule
, NULL
);
423 else if( p_media
!= NULL
)
424 *pp_status
= vlm_Show( p_vlm
, p_media
, NULL
, NULL
);
426 *pp_status
= vlm_Show( p_vlm
, NULL
, NULL
, psz_name
);
431 static int ExecuteHelp( vlm_message_t
*p_status
)
433 vlm_message_t
*message_child
;
435 #define MessageAdd( a ) \
436 vlm_MessageAdd( p_status, vlm_MessageNew( a, vlm_NULL ) );
437 #define MessageAddChild( a ) \
438 vlm_MessageAdd( message_child, vlm_MessageNew( a, vlm_NULL ) );
440 p_status
= vlm_MessageNew( "help", vlm_NULL
);
442 message_child
= MessageAdd( "Commands Syntax:" );
443 MessageAddChild( "new (name) vod|broadcast|schedule [properties]" );
444 MessageAddChild( "setup (name) (properties)" );
445 MessageAddChild( "show [(name)|media|schedule]" );
446 MessageAddChild( "del (name)|all|media|schedule" );
447 MessageAddChild( "control (name) [instance_name] (command)" );
448 MessageAddChild( "save (config_file)" );
449 MessageAddChild( "export" );
450 MessageAddChild( "load (config_file)" );
452 message_child
= MessageAdd( "Media Proprieties Syntax:" );
453 MessageAddChild( "input (input_name)" );
454 MessageAddChild( "inputdel (input_name)|all" );
455 MessageAddChild( "inputdeln input_number" );
456 MessageAddChild( "output (output_name)" );
457 MessageAddChild( "option (option_name)[=value]" );
458 MessageAddChild( "enabled|disabled" );
459 MessageAddChild( "loop|unloop (broadcast only)" );
460 MessageAddChild( "mux (mux_name)" );
462 message_child
= MessageAdd( "Schedule Proprieties Syntax:" );
463 MessageAddChild( "enabled|disabled" );
464 MessageAddChild( "append (command_until_rest_of_the_line)" );
465 MessageAddChild( "date (year)/(month)/(day)-(hour):(minutes):"
467 MessageAddChild( "period (years_aka_12_months)/(months_aka_30_days)/"
468 "(days)-(hours):(minutes):(seconds)" );
469 MessageAddChild( "repeat (number_of_repetitions)" );
471 message_child
= MessageAdd( "Control Commands Syntax:" );
472 MessageAddChild( "play [input_number]" );
473 MessageAddChild( "pause" );
474 MessageAddChild( "stop" );
475 MessageAddChild( "seek [+-](percentage) | [+-](seconds)s | [+-](miliseconds)ms" );
480 static int ExecuteControl( vlm_t
*p_vlm
, const char *psz_name
, const int i_arg
, char ** ppsz_arg
, vlm_message_t
**pp_status
)
482 vlm_media_sys_t
*p_media
;
483 const char *psz_control
= NULL
;
484 const char *psz_instance
= NULL
;
485 const char *psz_argument
= NULL
;
489 if( !ExecuteIsMedia( p_vlm
, psz_name
) )
491 *pp_status
= vlm_MessageNew( "control", "%s: media unknown", psz_name
);
497 #define IS(txt) ( !strcmp( ppsz_arg[i_index], (txt) ) )
499 if( !IS("play") && !IS("stop") && !IS("pause") && !IS("seek") )
502 psz_instance
= ppsz_arg
[0];
504 if( i_index
>= i_arg
|| ( !IS("play") && !IS("stop") && !IS("pause") && !IS("seek") ) )
505 return ExecuteSyntaxError( "control", pp_status
);
508 psz_control
= ppsz_arg
[i_index
];
510 if( i_index
+1 < i_arg
)
511 psz_argument
= ppsz_arg
[i_index
+1];
513 p_media
= vlm_MediaSearch( p_vlm
, psz_name
);
516 if( !strcmp( psz_control
, "play" ) )
518 int i_input_index
= 0;
521 if( ( psz_argument
&& sscanf(psz_argument
, "%d", &i
) == 1 ) && i
> 0 && i
-1 < p_media
->cfg
.i_input
)
525 else if( psz_argument
)
528 vlm_media_t
*p_cfg
= &p_media
->cfg
;
529 for ( j
=0; j
< p_cfg
->i_input
; j
++)
531 if( !strcmp( p_cfg
->ppsz_input
[j
], psz_argument
) )
539 if( p_media
->cfg
.b_vod
)
540 i_result
= vlm_ControlInternal( p_vlm
, VLM_START_MEDIA_VOD_INSTANCE
, p_media
->cfg
.id
, psz_instance
, i_input_index
, NULL
); // we should get here now
542 i_result
= vlm_ControlInternal( p_vlm
, VLM_START_MEDIA_BROADCAST_INSTANCE
, p_media
->cfg
.id
, psz_instance
, i_input_index
);
544 else if( !strcmp( psz_control
, "seek" ) )
548 vlc_bool_t b_relative
;
549 if( psz_argument
[0] == '+' || psz_argument
[0] == '-' )
550 b_relative
= VLC_TRUE
;
552 b_relative
= VLC_FALSE
;
554 if( strstr( psz_argument
, "ms" ) || strstr( psz_argument
, "s" ) )
559 if( strstr( psz_argument
, "ms" ) )
560 i_new_time
= 1000 * (int64_t)atoi( psz_argument
);
562 i_new_time
= 1000000 * (int64_t)atoi( psz_argument
);
567 vlm_ControlInternal( p_vlm
, VLM_GET_MEDIA_INSTANCE_TIME
, p_media
->cfg
.id
, psz_instance
, &i_time
);
568 i_new_time
+= i_time
;
572 i_result
= vlm_ControlInternal( p_vlm
, VLM_SET_MEDIA_INSTANCE_TIME
, p_media
->cfg
.id
, psz_instance
, i_new_time
);
577 double d_new_position
= i18n_atof( psz_argument
) / 100.0;
581 double d_position
= 0.0;
583 vlm_ControlInternal( p_vlm
, VLM_GET_MEDIA_INSTANCE_POSITION
, p_media
->cfg
.id
, psz_instance
, &d_position
);
584 d_new_position
+= d_position
;
586 if( d_new_position
< 0.0 )
587 d_new_position
= 0.0;
588 else if( d_new_position
> 1.0 )
589 d_new_position
= 1.0;
590 i_result
= vlm_ControlInternal( p_vlm
, VLM_SET_MEDIA_INSTANCE_POSITION
, p_media
->cfg
.id
, psz_instance
, d_new_position
);
595 i_result
= VLC_EGENERIC
;
598 else if( !strcmp( psz_control
, "rewind" ) )
602 const double d_scale
= i18n_atof( psz_argument
);
605 vlm_ControlInternal( p_vlm
, VLM_GET_MEDIA_INSTANCE_POSITION
, p_media
->cfg
.id
, psz_instance
, &d_position
);
606 d_position
-= (d_scale
/ 1000.0);
607 if( d_position
< 0.0 )
609 i_result
= vlm_ControlInternal( p_vlm
, VLM_SET_MEDIA_INSTANCE_POSITION
, p_media
->cfg
.id
, psz_instance
, d_position
);
613 i_result
= VLC_EGENERIC
;
616 else if( !strcmp( psz_control
, "forward" ) )
620 const double d_scale
= i18n_atof( psz_argument
);
623 vlm_ControlInternal( p_vlm
, VLM_GET_MEDIA_INSTANCE_POSITION
, p_media
->cfg
.id
, psz_instance
, &d_position
);
624 d_position
+= (d_scale
/ 1000.0);
625 if( d_position
> 1.0 )
627 i_result
= vlm_ControlInternal( p_vlm
, VLM_SET_MEDIA_INSTANCE_POSITION
, p_media
->cfg
.id
, psz_instance
, d_position
);
632 i_result
= VLC_EGENERIC
;
635 else if( !strcmp( psz_control
, "stop" ) )
637 i_result
= vlm_ControlInternal( p_vlm
, VLM_STOP_MEDIA_INSTANCE
, p_media
->cfg
.id
, psz_instance
);
639 else if( !strcmp( psz_control
, "pause" ) )
641 i_result
= vlm_ControlInternal( p_vlm
, VLM_PAUSE_MEDIA_INSTANCE
, p_media
->cfg
.id
, psz_instance
);
645 i_result
= VLC_EGENERIC
;
650 *pp_status
= vlm_MessageNew( "control", "unknown error" );
653 *pp_status
= vlm_MessageNew( "control", vlm_NULL
);
657 static int ExecuteExport( vlm_t
*p_vlm
, vlm_message_t
**pp_status
)
659 char *psz_export
= Save( p_vlm
);
661 *pp_status
= vlm_MessageNew( "export", psz_export
);
666 static int ExecuteSave( vlm_t
*p_vlm
, const char *psz_file
, vlm_message_t
**pp_status
)
668 FILE *f
= utf8_fopen( psz_file
, "wt" );
674 psz_save
= Save( p_vlm
);
675 if( psz_save
== NULL
)
680 fwrite( psz_save
, strlen( psz_save
), 1, f
);
684 *pp_status
= vlm_MessageNew( "save", vlm_NULL
);
688 *pp_status
= vlm_MessageNew( "save", "Unable to save to file" );
692 static int ExecuteLoad( vlm_t
*p_vlm
, const char *psz_url
, vlm_message_t
**pp_status
)
694 stream_t
*p_stream
= stream_UrlNew( p_vlm
, psz_url
);
700 *pp_status
= vlm_MessageNew( "load", "Unable to load from file" );
705 if( stream_Seek( p_stream
, 0 ) != 0 )
707 stream_Delete( p_stream
);
709 *pp_status
= vlm_MessageNew( "load", "Read file error" );
713 i_size
= stream_Size( p_stream
);
715 psz_buffer
= malloc( i_size
+ 1 );
718 stream_Delete( p_stream
);
720 *pp_status
= vlm_MessageNew( "load", "Read file error" );
724 stream_Read( p_stream
, psz_buffer
, i_size
);
725 psz_buffer
[i_size
] = '\0';
727 stream_Delete( p_stream
);
729 if( Load( p_vlm
, psz_buffer
) )
733 *pp_status
= vlm_MessageNew( "load", "Error while loading file" );
739 *pp_status
= vlm_MessageNew( "load", vlm_NULL
);
743 static int ExecuteScheduleProperty( vlm_t
*p_vlm
, vlm_schedule_sys_t
*p_schedule
, vlc_bool_t b_new
,
744 const int i_property
, char *ppsz_property
[], vlm_message_t
**pp_status
)
746 const char *psz_cmd
= b_new
? "new" : "setup";
749 for( i
= 0; i
< i_property
; i
++ )
751 if( !strcmp( ppsz_property
[i
], "enabled" ) ||
752 !strcmp( ppsz_property
[i
], "disabled" ) )
754 vlm_ScheduleSetup( p_schedule
, ppsz_property
[i
], NULL
);
756 else if( !strcmp( ppsz_property
[i
], "append" ) )
760 /* Beware: everything behind append is considered as
763 if( ++i
>= i_property
)
766 psz_line
= strdup( ppsz_property
[i
] );
767 for( j
= i
+1; j
< i_property
; j
++ )
769 psz_line
= realloc( psz_line
, strlen(psz_line
) + strlen(ppsz_property
[j
]) + 1 + 1 );
770 strcat( psz_line
, " " );
771 strcat( psz_line
, ppsz_property
[j
] );
774 vlm_ScheduleSetup( p_schedule
, "append", psz_line
);
779 if( i
+ 1 >= i_property
)
782 vlm_ScheduleDelete( p_vlm
, p_schedule
);
783 return ExecuteSyntaxError( psz_cmd
, pp_status
);
786 vlm_ScheduleSetup( p_schedule
, ppsz_property
[i
], ppsz_property
[i
+1] );
790 *pp_status
= vlm_MessageNew( psz_cmd
, vlm_NULL
);
794 static int ExecuteMediaProperty( vlm_t
*p_vlm
, int64_t id
, vlc_bool_t b_new
,
795 const int i_property
, char *ppsz_property
[], vlm_message_t
**pp_status
)
797 const char *psz_cmd
= b_new
? "new" : "setup";
798 vlm_media_t
*p_cfg
= NULL
;
804 #define ERROR( txt ) do { *pp_status = vlm_MessageNew( psz_cmd, txt); goto error; } while(0)
805 if( vlm_ControlInternal( p_vlm
, VLM_GET_MEDIA
, id
, &p_cfg
) )
806 ERROR( "unknown media" );
808 #define MISSING(cmd) do { if( !psz_value ) ERROR( "missing argument for " cmd ); } while(0)
809 for( i
= 0; i
< i_property
; i
++ )
811 const char *psz_option
= ppsz_property
[i
];
812 const char *psz_value
= i
+1 < i_property
? ppsz_property
[i
+1] : NULL
;
814 if( !strcmp( psz_option
, "enabled" ) )
816 p_cfg
->b_enabled
= VLC_TRUE
;
818 else if( !strcmp( psz_option
, "disabled" ) )
820 p_cfg
->b_enabled
= VLC_FALSE
;
822 else if( !strcmp( psz_option
, "input" ) )
825 TAB_APPEND( p_cfg
->i_input
, p_cfg
->ppsz_input
, strdup(psz_value
) );
828 else if( !strcmp( psz_option
, "inputdel" ) && psz_value
&& !strcmp( psz_value
, "all" ) )
830 while( p_cfg
->i_input
> 0 )
831 TAB_REMOVE( p_cfg
->i_input
, p_cfg
->ppsz_input
, p_cfg
->ppsz_input
[0] );
834 else if( !strcmp( psz_option
, "inputdel" ) )
838 MISSING( "inputdel" );
840 for( j
= 0; j
< p_cfg
->i_input
; j
++ )
842 if( !strcmp( p_cfg
->ppsz_input
[j
], psz_value
) )
844 TAB_REMOVE( p_cfg
->i_input
, p_cfg
->ppsz_input
, p_cfg
->ppsz_input
[j
] );
850 else if( !strcmp( psz_option
, "inputdeln" ) )
854 MISSING( "inputdeln" );
856 i_index
= atoi( psz_value
);
857 if( i_index
> 0 && i_index
<= p_cfg
->i_input
)
858 TAB_REMOVE( p_cfg
->i_input
, p_cfg
->ppsz_input
, p_cfg
->ppsz_input
[i_index
-1] );
861 else if( !strcmp( psz_option
, "output" ) )
865 free( p_cfg
->psz_output
);
866 p_cfg
->psz_output
= *psz_value
? strdup( psz_value
) : NULL
;
869 else if( !strcmp( psz_option
, "option" ) )
873 TAB_APPEND( p_cfg
->i_option
, p_cfg
->ppsz_option
, strdup( psz_value
) );
876 else if( !strcmp( psz_option
, "loop" ) )
879 ERROR( "invalid loop option for vod" );
880 p_cfg
->broadcast
.b_loop
= VLC_TRUE
;
882 else if( !strcmp( psz_option
, "unloop" ) )
885 ERROR( "invalid unloop option for vod" );
886 p_cfg
->broadcast
.b_loop
= VLC_FALSE
;
888 else if( !strcmp( psz_option
, "mux" ) )
892 ERROR( "invalid mux option for broadcast" );
894 free( p_cfg
->vod
.psz_mux
);
895 p_cfg
->vod
.psz_mux
= *psz_value
? strdup( psz_value
) : NULL
;
900 fprintf( stderr
, "PROP: name=%s unknown\n", psz_option
);
901 ERROR( "Wrong command syntax" );
908 i_result
= vlm_ControlInternal( p_vlm
, VLM_CHANGE_MEDIA
, p_cfg
);
909 vlm_media_Delete( p_cfg
);
911 *pp_status
= vlm_MessageNew( psz_cmd
, vlm_NULL
);
918 vlm_ControlInternal( p_vlm
, VLM_DEL_MEDIA
, p_cfg
->id
);
919 vlm_media_Delete( p_cfg
);
924 static int ExecuteNew( vlm_t
*p_vlm
, const char *psz_name
, const char *psz_type
, const int i_property
, char *ppsz_property
[], vlm_message_t
**pp_status
)
927 if( !strcmp( psz_name
, "all" ) || !strcmp( psz_name
, "media" ) || !strcmp( psz_name
, "schedule" ) )
929 *pp_status
= vlm_MessageNew( "new", "\"all\", \"media\" and \"schedule\" are reserved names" );
932 if( ExecuteIsMedia( p_vlm
, psz_name
) || ExecuteIsSchedule( p_vlm
, psz_name
) )
934 *pp_status
= vlm_MessageNew( "new", "%s: Name already in use", psz_name
);
938 if( !strcmp( psz_type
, "schedule" ) )
940 vlm_schedule_sys_t
*p_schedule
= vlm_ScheduleNew( p_vlm
, psz_name
);
943 *pp_status
= vlm_MessageNew( "new", "could not create schedule" );
946 return ExecuteScheduleProperty( p_vlm
, p_schedule
, VLC_TRUE
, i_property
, ppsz_property
, pp_status
);
948 else if( !strcmp( psz_type
, "vod" ) || !strcmp( psz_type
, "broadcast" ) )
953 vlm_media_Init( &cfg
);
954 cfg
.psz_name
= strdup( psz_name
);
955 cfg
.b_vod
= !strcmp( psz_type
, "vod" );
957 if( vlm_ControlInternal( p_vlm
, VLM_ADD_MEDIA
, &cfg
, &id
) )
959 vlm_media_Clean( &cfg
);
960 *pp_status
= vlm_MessageNew( "new", "could not create media" );
963 vlm_media_Clean( &cfg
);
964 return ExecuteMediaProperty( p_vlm
, id
, VLC_TRUE
, i_property
, ppsz_property
, pp_status
);
968 *pp_status
= vlm_MessageNew( "new", "%s: Choose between vod, broadcast or schedule", psz_type
);
973 static int ExecuteSetup( vlm_t
*p_vlm
, const char *psz_name
, const int i_property
, char *ppsz_property
[], vlm_message_t
**pp_status
)
975 if( ExecuteIsSchedule( p_vlm
, psz_name
) )
977 vlm_schedule_sys_t
*p_schedule
= vlm_ScheduleSearch( p_vlm
, psz_name
);
978 return ExecuteScheduleProperty( p_vlm
, p_schedule
, VLC_FALSE
, i_property
, ppsz_property
, pp_status
);
980 else if( ExecuteIsMedia( p_vlm
, psz_name
) )
983 if( vlm_ControlInternal( p_vlm
, VLM_GET_MEDIA_ID
, psz_name
, &id
) )
985 return ExecuteMediaProperty( p_vlm
, id
, VLC_FALSE
, i_property
, ppsz_property
, pp_status
);
989 *pp_status
= vlm_MessageNew( "setup", "%s unknown", psz_name
);
993 static int ExecuteCommand( vlm_t
*p_vlm
, const char *psz_command
,
994 vlm_message_t
**pp_message
)
996 size_t i_command
= 0;
997 char buf
[strlen (psz_command
) + 1], *psz_buf
= buf
;
998 char *ppsz_command
[3+sizeof (buf
) / 2];
999 vlm_message_t
*p_message
= NULL
;
1001 /* First, parse the line and cut it */
1002 while( *psz_command
!= '\0' )
1004 const char *psz_temp
;
1006 if(isspace (*psz_command
))
1012 /* support for comments */
1013 if( i_command
== 0 && *psz_command
== '#')
1015 p_message
= vlm_MessageNew( "", vlm_NULL
);
1019 psz_temp
= FindCommandEnd( psz_command
);
1021 if( psz_temp
== NULL
)
1023 p_message
= vlm_MessageNew( "Incomplete command", psz_command
);
1027 assert (i_command
< (sizeof (ppsz_command
) / sizeof (ppsz_command
[0])));
1029 ppsz_command
[i_command
] = psz_buf
;
1030 memcpy (psz_buf
, psz_command
, psz_temp
- psz_command
);
1031 psz_buf
[psz_temp
- psz_command
] = '\0';
1033 Unescape (psz_buf
, psz_buf
);
1036 psz_buf
+= psz_temp
- psz_command
+ 1;
1037 psz_command
= psz_temp
;
1039 assert (buf
+ sizeof (buf
) >= psz_buf
);
1043 * And then Interpret it
1046 #define IF_EXECUTE( name, check, cmd ) if( !strcmp(ppsz_command[0], name ) ) { if( (check) ) goto syntax_error; if( (cmd) ) goto error; goto success; }
1047 if( i_command
== 0 )
1049 p_message
= vlm_MessageNew( "", vlm_NULL
);
1052 else IF_EXECUTE( "del", (i_command
!= 2), ExecuteDel(p_vlm
, ppsz_command
[1], &p_message
) )
1053 else IF_EXECUTE( "show", (i_command
> 2), ExecuteShow(p_vlm
, i_command
> 1 ? ppsz_command
[1] : NULL
, &p_message
) )
1054 else IF_EXECUTE( "help", (i_command
!= 1), ExecuteHelp( p_message
) )
1055 else IF_EXECUTE( "control", (i_command
< 3), ExecuteControl(p_vlm
, ppsz_command
[1], i_command
- 2, &ppsz_command
[2], &p_message
) )
1056 else IF_EXECUTE( "save", (i_command
!= 2), ExecuteSave(p_vlm
, ppsz_command
[1], &p_message
) )
1057 else IF_EXECUTE( "export", (i_command
!= 1), ExecuteExport(p_vlm
, &p_message
) )
1058 else IF_EXECUTE( "load", (i_command
!= 2), ExecuteLoad(p_vlm
, ppsz_command
[1], &p_message
) )
1059 else IF_EXECUTE( "new", (i_command
< 3), ExecuteNew(p_vlm
, ppsz_command
[1], ppsz_command
[2], i_command
-3, &ppsz_command
[3], &p_message
) )
1060 else IF_EXECUTE( "setup", (i_command
< 2), ExecuteSetup(p_vlm
, ppsz_command
[1], i_command
-2, &ppsz_command
[2], &p_message
) )
1063 p_message
= vlm_MessageNew( ppsz_command
[0], "Unknown command" );
1069 *pp_message
= p_message
;
1073 return ExecuteSyntaxError( ppsz_command
[0], pp_message
);
1076 *pp_message
= p_message
;
1077 return VLC_EGENERIC
;
1080 /*****************************************************************************
1082 *****************************************************************************/
1083 vlm_media_sys_t
*vlm_MediaSearch( vlm_t
*vlm
, const char *psz_name
)
1087 for( i
= 0; i
< vlm
->i_media
; i
++ )
1089 if( strcmp( psz_name
, vlm
->media
[i
]->cfg
.psz_name
) == 0 )
1090 return vlm
->media
[i
];
1096 /*****************************************************************************
1098 *****************************************************************************/
1099 static int64_t vlm_Date(void)
1104 return ((int64_t)tm
.time
) * 1000000 + ((int64_t)tm
.millitm
) * 1000;
1106 struct timeval tv_date
;
1108 /* gettimeofday() cannot fail given &tv_date is a valid address */
1109 (void)gettimeofday( &tv_date
, NULL
);
1110 return (mtime_t
) tv_date
.tv_sec
* 1000000 + (mtime_t
) tv_date
.tv_usec
;
1114 static vlm_schedule_sys_t
*vlm_ScheduleNew( vlm_t
*vlm
, const char *psz_name
)
1116 vlm_schedule_sys_t
*p_sched
= malloc( sizeof( vlm_schedule_sys_t
) );
1128 p_sched
->psz_name
= strdup( psz_name
);
1129 p_sched
->b_enabled
= VLC_FALSE
;
1130 p_sched
->i_command
= 0;
1131 p_sched
->command
= NULL
;
1132 p_sched
->i_date
= 0;
1133 p_sched
->i_period
= 0;
1134 p_sched
->i_repeat
= -1;
1136 TAB_APPEND( vlm
->i_schedule
, vlm
->schedule
, p_sched
);
1141 /* for now, simple delete. After, del with options (last arg) */
1142 static void vlm_ScheduleDelete( vlm_t
*vlm
, vlm_schedule_sys_t
*sched
)
1144 if( sched
== NULL
) return;
1146 TAB_REMOVE( vlm
->i_schedule
, vlm
->schedule
, sched
);
1148 if( vlm
->i_schedule
== 0 ) free( vlm
->schedule
);
1149 free( sched
->psz_name
);
1150 while( sched
->i_command
)
1152 char *psz_cmd
= sched
->command
[0];
1153 TAB_REMOVE( sched
->i_command
, sched
->command
, psz_cmd
);
1159 static vlm_schedule_sys_t
*vlm_ScheduleSearch( vlm_t
*vlm
, const char *psz_name
)
1163 for( i
= 0; i
< vlm
->i_schedule
; i
++ )
1165 if( strcmp( psz_name
, vlm
->schedule
[i
]->psz_name
) == 0 )
1167 return vlm
->schedule
[i
];
1174 /* Ok, setup schedule command will be able to support only one (argument value) at a time */
1175 static int vlm_ScheduleSetup( vlm_schedule_sys_t
*schedule
, const char *psz_cmd
,
1176 const char *psz_value
)
1178 if( !strcmp( psz_cmd
, "enabled" ) )
1180 schedule
->b_enabled
= VLC_TRUE
;
1182 else if( !strcmp( psz_cmd
, "disabled" ) )
1184 schedule
->b_enabled
= VLC_FALSE
;
1186 #if !defined( UNDER_CE )
1187 else if( !strcmp( psz_cmd
, "date" ) )
1193 time
.tm_sec
= 0; /* seconds */
1194 time
.tm_min
= 0; /* minutes */
1195 time
.tm_hour
= 0; /* hours */
1196 time
.tm_mday
= 0; /* day of the month */
1197 time
.tm_mon
= 0; /* month */
1198 time
.tm_year
= 0; /* year */
1199 time
.tm_wday
= 0; /* day of the week */
1200 time
.tm_yday
= 0; /* day in the year */
1201 time
.tm_isdst
= -1; /* daylight saving time */
1203 /* date should be year/month/day-hour:minutes:seconds */
1204 p
= strchr( psz_value
, '-' );
1206 if( !strcmp( psz_value
, "now" ) )
1208 schedule
->i_date
= 0;
1210 else if( (p
== NULL
) && sscanf( psz_value
, "%d:%d:%d", &time
.tm_hour
,
1211 &time
.tm_min
, &time
.tm_sec
) != 3 )
1212 /* it must be a hour:minutes:seconds */
1220 switch( sscanf( p
+ 1, "%u:%u:%u", &i
, &j
, &k
) )
1238 switch( sscanf( psz_value
, "%d/%d/%d", &i
, &j
, &k
) )
1244 time
.tm_mon
= i
- 1;
1248 time
.tm_year
= i
- 1900;
1249 time
.tm_mon
= j
- 1;
1256 date
= mktime( &time
);
1257 schedule
->i_date
= ((mtime_t
) date
) * 1000000;
1260 else if( !strcmp( psz_cmd
, "period" ) )
1264 const char *psz_time
= NULL
, *psz_date
= NULL
;
1268 /* First, if date or period are modified, repeat should be equal to -1 */
1269 schedule
->i_repeat
= -1;
1271 time
.tm_sec
= 0; /* seconds */
1272 time
.tm_min
= 0; /* minutes */
1273 time
.tm_hour
= 0; /* hours */
1274 time
.tm_mday
= 0; /* day of the month */
1275 time
.tm_mon
= 0; /* month */
1276 time
.tm_year
= 0; /* year */
1277 time
.tm_wday
= 0; /* day of the week */
1278 time
.tm_yday
= 0; /* day in the year */
1279 time
.tm_isdst
= -1; /* daylight saving time */
1281 /* date should be year/month/day-hour:minutes:seconds */
1282 p
= strchr( psz_value
, '-' );
1285 psz_date
= psz_value
;
1290 psz_time
= psz_value
;
1293 switch( sscanf( psz_time
, "%u:%u:%u", &i
, &j
, &k
) )
1312 switch( sscanf( psz_date
, "%u/%u/%u", &i
, &j
, &k
) )
1331 /* ok, that's stupid... who is going to schedule streams every 42 years ? */
1332 date
= (((( time
.tm_year
* 12 + time
.tm_mon
) * 30 + time
.tm_mday
) * 24 + time
.tm_hour
) * 60 + time
.tm_min
) * 60 + time
.tm_sec
;
1333 schedule
->i_period
= ((mtime_t
) date
) * 1000000;
1335 #endif /* UNDER_CE */
1336 else if( !strcmp( psz_cmd
, "repeat" ) )
1340 if( sscanf( psz_value
, "%d", &i
) == 1 )
1342 schedule
->i_repeat
= i
;
1349 else if( !strcmp( psz_cmd
, "append" ) )
1351 char *command
= strdup( psz_value
);
1353 TAB_APPEND( schedule
->i_command
, schedule
->command
, command
);
1362 /*****************************************************************************
1363 * Message handling functions
1364 *****************************************************************************/
1365 vlm_message_t
*vlm_MessageNew( const char *psz_name
,
1366 const char *psz_format
, ... )
1368 vlm_message_t
*p_message
;
1371 if( !psz_name
) return NULL
;
1373 p_message
= malloc( sizeof(vlm_message_t
) );
1379 p_message
->psz_value
= 0;
1383 va_start( args
, psz_format
);
1384 if( vasprintf( &p_message
->psz_value
, psz_format
, args
) == -1 )
1393 p_message
->psz_name
= strdup( psz_name
);
1394 p_message
->i_child
= 0;
1395 p_message
->child
= NULL
;
1400 void vlm_MessageDelete( vlm_message_t
*p_message
)
1402 free( p_message
->psz_name
);
1403 free( p_message
->psz_value
);
1404 while( p_message
->i_child
-- )
1405 vlm_MessageDelete( p_message
->child
[p_message
->i_child
] );
1406 free( p_message
->child
);
1411 vlm_message_t
*vlm_MessageAdd( vlm_message_t
*p_message
,
1412 vlm_message_t
*p_child
)
1414 if( p_message
== NULL
) return NULL
;
1418 TAB_APPEND( p_message
->i_child
, p_message
->child
, p_child
);
1424 /*****************************************************************************
1425 * Misc utility functions
1426 *****************************************************************************/
1427 static vlm_message_t
*vlm_ShowMedia( vlm_media_sys_t
*p_media
)
1429 vlm_media_t
*p_cfg
= &p_media
->cfg
;
1430 vlm_message_t
*p_msg
;
1431 vlm_message_t
*p_msg_sub
;
1434 p_msg
= vlm_MessageNew( p_cfg
->psz_name
, vlm_NULL
);
1435 vlm_MessageAdd( p_msg
,
1436 vlm_MessageNew( "type", p_cfg
->b_vod
? "vod" : "broadcast" ) );
1437 vlm_MessageAdd( p_msg
,
1438 vlm_MessageNew( "enabled", p_cfg
->b_enabled
? "yes" : "no" ) );
1441 vlm_MessageAdd( p_msg
,
1442 vlm_MessageNew( "mux", p_cfg
->vod
.psz_mux
) );
1444 vlm_MessageAdd( p_msg
,
1445 vlm_MessageNew( "loop", p_cfg
->broadcast
.b_loop
? "yes" : "no" ) );
1447 p_msg_sub
= vlm_MessageAdd( p_msg
, vlm_MessageNew( "inputs", vlm_NULL
) );
1448 for( i
= 0; i
< p_cfg
->i_input
; i
++ )
1451 asprintf( &psz_tmp
, "%d", i
+1 );
1452 vlm_MessageAdd( p_msg_sub
,
1453 vlm_MessageNew( psz_tmp
, p_cfg
->ppsz_input
[i
] ) );
1457 vlm_MessageAdd( p_msg
,
1458 vlm_MessageNew( "output", p_cfg
->psz_output
? p_cfg
->psz_output
: "" ) );
1460 p_msg_sub
= vlm_MessageAdd( p_msg
, vlm_MessageNew( "options", vlm_NULL
) );
1461 for( i
= 0; i
< p_cfg
->i_option
; i
++ )
1462 vlm_MessageAdd( p_msg_sub
, vlm_MessageNew( p_cfg
->ppsz_option
[i
], vlm_NULL
) );
1464 p_msg_sub
= vlm_MessageAdd( p_msg
, vlm_MessageNew( "instances", vlm_NULL
) );
1465 for( i
= 0; i
< p_media
->i_instance
; i
++ )
1467 vlm_media_instance_sys_t
*p_instance
= p_media
->instance
[i
];
1469 vlm_message_t
*p_msg_instance
;
1473 if( p_instance
->p_input
)
1474 var_Get( p_instance
->p_input
, "state", &val
);
1476 p_msg_instance
= vlm_MessageAdd( p_msg_sub
, vlm_MessageNew( "instance" , vlm_NULL
) );
1478 vlm_MessageAdd( p_msg_instance
,
1479 vlm_MessageNew( "name" , p_instance
->psz_name
? p_instance
->psz_name
: "default" ) );
1480 vlm_MessageAdd( p_msg_instance
,
1481 vlm_MessageNew( "state",
1482 val
.i_int
== PLAYING_S
? "playing" :
1483 val
.i_int
== PAUSE_S
? "paused" :
1486 /* FIXME should not do that this way */
1487 if( p_instance
->p_input
)
1489 #define APPEND_INPUT_INFO( a, format, type ) \
1490 asprintf( &psz_tmp, format, \
1491 var_Get ## type( p_instance->p_input, a ) ); \
1492 vlm_MessageAdd( p_msg_instance, vlm_MessageNew( a, psz_tmp ) ); \
1494 APPEND_INPUT_INFO( "position", "%f", Float
);
1495 APPEND_INPUT_INFO( "time", I64Fi
, Time
);
1496 APPEND_INPUT_INFO( "length", I64Fi
, Time
);
1497 APPEND_INPUT_INFO( "rate", "%d", Integer
);
1498 APPEND_INPUT_INFO( "title", "%d", Integer
);
1499 APPEND_INPUT_INFO( "chapter", "%d", Integer
);
1500 APPEND_INPUT_INFO( "seekable", "%d", Bool
);
1502 #undef APPEND_INPUT_INFO
1503 asprintf( &psz_tmp
, "%d", p_instance
->i_index
+ 1 );
1504 vlm_MessageAdd( p_msg_instance
, vlm_MessageNew( "playlistindex", psz_tmp
) );
1510 static vlm_message_t
*vlm_Show( vlm_t
*vlm
, vlm_media_sys_t
*media
,
1511 vlm_schedule_sys_t
*schedule
,
1512 const char *psz_filter
)
1516 vlm_message_t
*p_msg
= vlm_MessageNew( "show", vlm_NULL
);
1518 vlm_MessageAdd( p_msg
, vlm_ShowMedia( media
) );
1522 else if( schedule
!= NULL
)
1526 vlm_message_t
*msg_schedule
;
1527 vlm_message_t
*msg_child
;
1530 msg
= vlm_MessageNew( "show", vlm_NULL
);
1532 vlm_MessageAdd( msg
, vlm_MessageNew( schedule
->psz_name
, vlm_NULL
) );
1534 vlm_MessageAdd( msg_schedule
, vlm_MessageNew("type", "schedule") );
1536 vlm_MessageAdd( msg_schedule
,
1537 vlm_MessageNew( "enabled", schedule
->b_enabled
?
1540 #if !defined( UNDER_CE )
1541 if( schedule
->i_date
!= 0 )
1544 time_t i_time
= (time_t)( schedule
->i_date
/ 1000000 );
1547 #ifdef HAVE_LOCALTIME_R
1548 localtime_r( &i_time
, &date
);
1550 struct tm
*p_date
= localtime( &i_time
);
1554 asprintf( &psz_date
, "%d/%d/%d-%d:%d:%d",
1555 date
.tm_year
+ 1900, date
.tm_mon
+ 1, date
.tm_mday
,
1556 date
.tm_hour
, date
.tm_min
, date
.tm_sec
);
1558 vlm_MessageAdd( msg_schedule
,
1559 vlm_MessageNew( "date", psz_date
) );
1564 vlm_MessageAdd( msg_schedule
, vlm_MessageNew("date", "now") );
1567 if( schedule
->i_period
!= 0 )
1569 time_t i_time
= (time_t) ( schedule
->i_period
/ 1000000 );
1572 date
.tm_sec
= (int)( i_time
% 60 );
1573 i_time
= i_time
/ 60;
1574 date
.tm_min
= (int)( i_time
% 60 );
1575 i_time
= i_time
/ 60;
1576 date
.tm_hour
= (int)( i_time
% 24 );
1577 i_time
= i_time
/ 24;
1578 date
.tm_mday
= (int)( i_time
% 30 );
1579 i_time
= i_time
/ 30;
1580 /* okay, okay, months are not always 30 days long */
1581 date
.tm_mon
= (int)( i_time
% 12 );
1582 i_time
= i_time
/ 12;
1583 date
.tm_year
= (int)i_time
;
1585 sprintf( buffer
, "%d/%d/%d-%d:%d:%d", date
.tm_year
, date
.tm_mon
,
1586 date
.tm_mday
, date
.tm_hour
, date
.tm_min
, date
.tm_sec
);
1588 vlm_MessageAdd( msg_schedule
, vlm_MessageNew("period", buffer
) );
1592 vlm_MessageAdd( msg_schedule
, vlm_MessageNew("period", "0") );
1594 #endif /* UNDER_CE */
1596 sprintf( buffer
, "%d", schedule
->i_repeat
);
1597 vlm_MessageAdd( msg_schedule
, vlm_MessageNew( "repeat", buffer
) );
1600 vlm_MessageAdd( msg_schedule
, vlm_MessageNew("commands", vlm_NULL
) );
1602 for( i
= 0; i
< schedule
->i_command
; i
++ )
1604 vlm_MessageAdd( msg_child
,
1605 vlm_MessageNew( schedule
->command
[i
], vlm_NULL
) );
1612 else if( psz_filter
&& !strcmp( psz_filter
, "media" ) )
1614 vlm_message_t
*p_msg
;
1615 vlm_message_t
*p_msg_child
;
1616 int i_vod
= 0, i_broadcast
= 0;
1620 for( i
= 0; i
< vlm
->i_media
; i
++ )
1622 if( vlm
->media
[i
]->cfg
.b_vod
)
1628 asprintf( &psz_count
, "( %d broadcast - %d vod )", i_broadcast
, i_vod
);
1630 p_msg
= vlm_MessageNew( "show", vlm_NULL
);
1631 p_msg_child
= vlm_MessageAdd( p_msg
, vlm_MessageNew( "media", psz_count
) );
1634 for( i
= 0; i
< vlm
->i_media
; i
++ )
1635 vlm_MessageAdd( p_msg_child
, vlm_ShowMedia( vlm
->media
[i
] ) );
1640 else if( psz_filter
&& !strcmp( psz_filter
, "schedule" ) )
1644 vlm_message_t
*msg_child
;
1646 msg
= vlm_MessageNew( "show", vlm_NULL
);
1647 msg_child
= vlm_MessageAdd( msg
, vlm_MessageNew( "schedule", vlm_NULL
) );
1649 for( i
= 0; i
< vlm
->i_schedule
; i
++ )
1651 vlm_schedule_sys_t
*s
= vlm
->schedule
[i
];
1652 vlm_message_t
*msg_schedule
;
1653 mtime_t i_time
, i_next_date
;
1655 msg_schedule
= vlm_MessageAdd( msg_child
,
1656 vlm_MessageNew( s
->psz_name
, vlm_NULL
) );
1657 vlm_MessageAdd( msg_schedule
,
1658 vlm_MessageNew( "enabled", s
->b_enabled
?
1661 /* calculate next date */
1662 i_time
= vlm_Date();
1663 i_next_date
= s
->i_date
;
1665 if( s
->i_period
!= 0 )
1668 while( s
->i_date
+ j
* s
->i_period
<= i_time
&&
1674 i_next_date
= s
->i_date
+ j
* s
->i_period
;
1677 if( i_next_date
> i_time
)
1679 time_t i_date
= (time_t) (i_next_date
/ 1000000) ;
1681 #if !defined( UNDER_CE )
1684 ctime_r( &i_date
, psz_date
);
1686 char *psz_date
= ctime( &i_date
);
1689 vlm_MessageAdd( msg_schedule
,
1690 vlm_MessageNew( "next launch", psz_date
) );
1698 else if( ( psz_filter
== NULL
) && ( media
== NULL
) && ( schedule
== NULL
) )
1700 vlm_message_t
*show1
= vlm_Show( vlm
, NULL
, NULL
, "media" );
1701 vlm_message_t
*show2
= vlm_Show( vlm
, NULL
, NULL
, "schedule" );
1703 vlm_MessageAdd( show1
, show2
->child
[0] );
1705 /* We must destroy the parent node "show" of show2
1706 * and not the children */
1707 free( show2
->psz_name
);
1715 return vlm_MessageNew( "show", vlm_NULL
);
1719 /*****************************************************************************
1720 * Config handling functions
1721 *****************************************************************************/
1722 static int Load( vlm_t
*vlm
, char *file
)
1727 while( *pf
!= '\0' )
1729 vlm_message_t
*message
= NULL
;
1732 while( pf
[i_end
] != '\n' && pf
[i_end
] != '\0' && pf
[i_end
] != '\r' )
1737 if( pf
[i_end
] == '\r' || pf
[i_end
] == '\n' )
1741 if( pf
[i_end
] == '\n' ) i_end
++;
1744 if( *pf
&& ExecuteCommand( vlm
, pf
, &message
) )
1748 if( message
->psz_value
)
1749 msg_Err( vlm
, "Load error on line %d: %s: %s",
1750 i_line
, message
->psz_name
, message
->psz_value
);
1751 vlm_MessageDelete( message
);
1755 if( message
) vlm_MessageDelete( message
);
1764 static char *Save( vlm_t
*vlm
)
1767 char psz_header
[] = "\n"
1768 "# VLC media player VLM command batch\n"
1769 "# http://www.videolan.org/vlc/\n\n" ;
1772 int i_length
= strlen( psz_header
);
1774 for( i
= 0; i
< vlm
->i_media
; i
++ )
1776 vlm_media_sys_t
*media
= vlm
->media
[i
];
1777 vlm_media_t
*p_cfg
= &media
->cfg
;
1780 i_length
+= strlen( "new * vod " ) + strlen(p_cfg
->psz_name
);
1782 i_length
+= strlen( "new * broadcast " ) + strlen(p_cfg
->psz_name
);
1784 if( p_cfg
->b_enabled
== VLC_TRUE
)
1785 i_length
+= strlen( "enabled" );
1787 i_length
+= strlen( "disabled" );
1789 if( !p_cfg
->b_vod
&& p_cfg
->broadcast
.b_loop
== VLC_TRUE
)
1790 i_length
+= strlen( " loop\n" );
1792 i_length
+= strlen( "\n" );
1794 for( j
= 0; j
< p_cfg
->i_input
; j
++ )
1795 i_length
+= strlen( "setup * input \"\"\n" ) + strlen( p_cfg
->psz_name
) + strlen( p_cfg
->ppsz_input
[j
] );
1797 if( p_cfg
->psz_output
!= NULL
)
1798 i_length
+= strlen( "setup * output \n" ) + strlen(p_cfg
->psz_name
) + strlen(p_cfg
->psz_output
);
1800 for( j
= 0; j
< p_cfg
->i_option
; j
++ )
1801 i_length
+= strlen("setup * option \n") + strlen(p_cfg
->psz_name
) + strlen(p_cfg
->ppsz_option
[j
]);
1803 if( p_cfg
->b_vod
&& p_cfg
->vod
.psz_mux
)
1804 i_length
+= strlen("setup * mux \n") + strlen(p_cfg
->psz_name
) + strlen(p_cfg
->vod
.psz_mux
);
1807 for( i
= 0; i
< vlm
->i_schedule
; i
++ )
1809 vlm_schedule_sys_t
*schedule
= vlm
->schedule
[i
];
1811 i_length
+= strlen( "new schedule " ) + strlen( schedule
->psz_name
);
1813 if( schedule
->b_enabled
== VLC_TRUE
)
1815 i_length
+= strlen( "date //-:: enabled\n" ) + 14;
1819 i_length
+= strlen( "date //-:: disabled\n" ) + 14;
1823 if( schedule
->i_period
!= 0 )
1825 i_length
+= strlen( "setup " ) + strlen( schedule
->psz_name
) +
1826 strlen( "period //-::\n" ) + 14;
1829 if( schedule
->i_repeat
>= 0 )
1833 sprintf( buffer
, "%d", schedule
->i_repeat
);
1834 i_length
+= strlen( "setup repeat \n" ) +
1835 strlen( schedule
->psz_name
) + strlen( buffer
);
1842 for( j
= 0; j
< schedule
->i_command
; j
++ )
1844 i_length
+= strlen( "setup append \n" ) +
1845 strlen( schedule
->psz_name
) + strlen( schedule
->command
[j
] );
1850 /* Don't forget the '\0' */
1852 /* now we have the length of save */
1854 p
= save
= malloc( i_length
);
1855 if( !save
) return NULL
;
1858 p
+= sprintf( p
, "%s", psz_header
);
1860 /* finally we can write in it */
1861 for( i
= 0; i
< vlm
->i_media
; i
++ )
1863 vlm_media_sys_t
*media
= vlm
->media
[i
];
1864 vlm_media_t
*p_cfg
= &media
->cfg
;
1867 p
+= sprintf( p
, "new %s vod ", p_cfg
->psz_name
);
1869 p
+= sprintf( p
, "new %s broadcast ", p_cfg
->psz_name
);
1871 if( p_cfg
->b_enabled
)
1872 p
+= sprintf( p
, "enabled" );
1874 p
+= sprintf( p
, "disabled" );
1876 if( !p_cfg
->b_vod
&& p_cfg
->broadcast
.b_loop
)
1877 p
+= sprintf( p
, " loop\n" );
1879 p
+= sprintf( p
, "\n" );
1881 for( j
= 0; j
< p_cfg
->i_input
; j
++ )
1882 p
+= sprintf( p
, "setup %s input \"%s\"\n", p_cfg
->psz_name
, p_cfg
->ppsz_input
[j
] );
1884 if( p_cfg
->psz_output
)
1885 p
+= sprintf( p
, "setup %s output %s\n", p_cfg
->psz_name
, p_cfg
->psz_output
);
1887 for( j
= 0; j
< p_cfg
->i_option
; j
++ )
1888 p
+= sprintf( p
, "setup %s option %s\n", p_cfg
->psz_name
, p_cfg
->ppsz_option
[j
] );
1890 if( p_cfg
->b_vod
&& p_cfg
->vod
.psz_mux
)
1891 p
+= sprintf( p
, "setup %s mux %s\n", p_cfg
->psz_name
, p_cfg
->vod
.psz_mux
);
1894 /* and now, the schedule scripts */
1895 #if !defined( UNDER_CE )
1896 for( i
= 0; i
< vlm
->i_schedule
; i
++ )
1898 vlm_schedule_sys_t
*schedule
= vlm
->schedule
[i
];
1900 time_t i_time
= (time_t) ( schedule
->i_date
/ 1000000 );
1902 #ifdef HAVE_LOCALTIME_R
1903 localtime_r( &i_time
, &date
);
1905 struct tm
*p_date
= localtime( &i_time
);
1909 p
+= sprintf( p
, "new %s schedule ", schedule
->psz_name
);
1911 if( schedule
->b_enabled
== VLC_TRUE
)
1913 p
+= sprintf( p
, "date %d/%d/%d-%d:%d:%d enabled\n",
1914 date
.tm_year
+ 1900, date
.tm_mon
+ 1, date
.tm_mday
,
1915 date
.tm_hour
, date
.tm_min
, date
.tm_sec
);
1919 p
+= sprintf( p
, "date %d/%d/%d-%d:%d:%d disabled\n",
1920 date
.tm_year
+ 1900, date
.tm_mon
+ 1, date
.tm_mday
,
1921 date
.tm_hour
, date
.tm_min
, date
.tm_sec
);
1924 if( schedule
->i_period
!= 0 )
1926 p
+= sprintf( p
, "setup %s ", schedule
->psz_name
);
1928 i_time
= (time_t) ( schedule
->i_period
/ 1000000 );
1930 date
.tm_sec
= (int)( i_time
% 60 );
1931 i_time
= i_time
/ 60;
1932 date
.tm_min
= (int)( i_time
% 60 );
1933 i_time
= i_time
/ 60;
1934 date
.tm_hour
= (int)( i_time
% 24 );
1935 i_time
= i_time
/ 24;
1936 date
.tm_mday
= (int)( i_time
% 30 );
1937 i_time
= i_time
/ 30;
1938 /* okay, okay, months are not always 30 days long */
1939 date
.tm_mon
= (int)( i_time
% 12 );
1940 i_time
= i_time
/ 12;
1941 date
.tm_year
= (int)i_time
;
1943 p
+= sprintf( p
, "period %d/%d/%d-%d:%d:%d\n",
1944 date
.tm_year
, date
.tm_mon
, date
.tm_mday
,
1945 date
.tm_hour
, date
.tm_min
, date
.tm_sec
);
1948 if( schedule
->i_repeat
>= 0 )
1950 p
+= sprintf( p
, "setup %s repeat %d\n",
1951 schedule
->psz_name
, schedule
->i_repeat
);
1955 p
+= sprintf( p
, "\n" );
1958 for( j
= 0; j
< schedule
->i_command
; j
++ )
1960 p
+= sprintf( p
, "setup %s append %s\n",
1961 schedule
->psz_name
, schedule
->command
[j
] );
1965 #endif /* UNDER_CE */
1970 /*****************************************************************************
1972 *****************************************************************************/
1973 static int vlm_MediaVodControl( void *p_private
, vod_media_t
*p_vod_media
,
1974 const char *psz_id
, int i_query
, va_list args
)
1976 vlm_t
*vlm
= (vlm_t
*)p_private
;
1981 if( !p_private
|| !p_vod_media
)
1982 return VLC_EGENERIC
;
1984 vlc_mutex_lock( &vlm
->lock
);
1987 for( i
= 0, id
= -1; i
< vlm
->i_media
; i
++ )
1989 if( p_vod_media
== vlm
->media
[i
]->vod
.p_media
)
1991 id
= vlm
->media
[i
]->cfg
.id
;
1997 vlc_mutex_unlock( &vlm
->lock
);
1998 return VLC_EGENERIC
;
2003 case VOD_MEDIA_PLAY
:
2004 psz
= (const char *)va_arg( args
, const char * );
2005 i_ret
= vlm_ControlInternal( vlm
, VLM_START_MEDIA_VOD_INSTANCE
, id
, psz_id
, 0, psz
);
2008 case VOD_MEDIA_PAUSE
:
2009 i_ret
= vlm_ControlInternal( vlm
, VLM_PAUSE_MEDIA_INSTANCE
, id
, psz_id
);
2012 case VOD_MEDIA_STOP
:
2013 i_ret
= vlm_ControlInternal( vlm
, VLM_STOP_MEDIA_INSTANCE
, id
, psz_id
);
2016 case VOD_MEDIA_SEEK
:
2018 double d_position
= (double)va_arg( args
, double );
2019 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, d_position
/100.0 );
2023 case VOD_MEDIA_REWIND
:
2025 double d_scale
= (double)va_arg( args
, double );
2028 vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, &d_position
);
2029 d_position
-= (d_scale
/ 1000.0);
2030 if( d_position
< 0.0 )
2032 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, d_position
);
2036 case VOD_MEDIA_FORWARD
:
2038 double d_scale
= (double)va_arg( args
, double );
2041 vlm_ControlInternal( vlm
, VLM_GET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, &d_position
);
2042 d_position
+= (d_scale
/ 1000.0);
2043 if( d_position
> 1.0 )
2045 i_ret
= vlm_ControlInternal( vlm
, VLM_SET_MEDIA_INSTANCE_POSITION
, id
, psz_id
, d_position
);
2050 i_ret
= VLC_EGENERIC
;
2054 vlc_mutex_unlock( &vlm
->lock
);
2060 /*****************************************************************************
2062 *****************************************************************************/
2063 static int Manage( vlc_object_t
* p_object
)
2065 vlm_t
*vlm
= (vlm_t
*)p_object
;
2067 mtime_t i_lastcheck
;
2070 i_lastcheck
= vlm_Date();
2072 while( !vlm
->b_die
)
2074 char **ppsz_scheduled_commands
= NULL
;
2075 int i_scheduled_commands
= 0;
2077 vlc_mutex_lock( &vlm
->lock
);
2079 /* destroy the inputs that wants to die, and launch the next input */
2080 for( i
= 0; i
< vlm
->i_media
; i
++ )
2082 vlm_media_sys_t
*p_media
= vlm
->media
[i
];
2084 for( j
= 0; j
< p_media
->i_instance
; )
2086 vlm_media_instance_sys_t
*p_instance
= p_media
->instance
[j
];
2088 if( p_instance
->p_input
&& ( p_instance
->p_input
->b_eof
|| p_instance
->p_input
->b_error
) )
2090 int i_new_input_index
;
2093 i_new_input_index
= p_instance
->i_index
+ 1;
2094 if( !p_media
->cfg
.b_vod
&& p_media
->cfg
.broadcast
.b_loop
&& i_new_input_index
>= p_media
->cfg
.i_input
)
2095 i_new_input_index
= 0;
2097 /* FIXME implement multiple input with VOD */
2098 if( p_media
->cfg
.b_vod
|| i_new_input_index
>= p_media
->cfg
.i_input
)
2099 vlm_ControlInternal( vlm
, VLM_STOP_MEDIA_INSTANCE
, p_media
->cfg
.id
, p_instance
->psz_name
);
2101 vlm_ControlInternal( vlm
, VLM_START_MEDIA_BROADCAST_INSTANCE
, p_media
->cfg
.id
, p_instance
->psz_name
, i_new_input_index
);
2113 i_time
= vlm_Date();
2115 for( i
= 0; i
< vlm
->i_schedule
; i
++ )
2117 mtime_t i_real_date
= vlm
->schedule
[i
]->i_date
;
2119 if( vlm
->schedule
[i
]->b_enabled
== VLC_TRUE
)
2121 if( vlm
->schedule
[i
]->i_date
== 0 ) // now !
2123 vlm
->schedule
[i
]->i_date
= (i_time
/ 1000000) * 1000000 ;
2124 i_real_date
= i_time
;
2126 else if( vlm
->schedule
[i
]->i_period
!= 0 )
2129 while( vlm
->schedule
[i
]->i_date
+ j
*
2130 vlm
->schedule
[i
]->i_period
<= i_lastcheck
&&
2131 ( vlm
->schedule
[i
]->i_repeat
> j
||
2132 vlm
->schedule
[i
]->i_repeat
== -1 ) )
2137 i_real_date
= vlm
->schedule
[i
]->i_date
+ j
*
2138 vlm
->schedule
[i
]->i_period
;
2141 if( i_real_date
<= i_time
&& i_real_date
> i_lastcheck
)
2143 for( j
= 0; j
< vlm
->schedule
[i
]->i_command
; j
++ )
2145 TAB_APPEND( i_scheduled_commands
,
2146 ppsz_scheduled_commands
,
2147 strdup(vlm
->schedule
[i
]->command
[j
] ) );
2152 while( i_scheduled_commands
)
2154 vlm_message_t
*message
= NULL
;
2155 char *psz_command
= ppsz_scheduled_commands
[0];
2156 ExecuteCommand( vlm
, psz_command
,&message
);
2158 /* for now, drop the message */
2159 vlm_MessageDelete( message
);
2160 TAB_REMOVE( i_scheduled_commands
,
2161 ppsz_scheduled_commands
,
2163 free( psz_command
);
2166 i_lastcheck
= i_time
;
2168 vlc_mutex_unlock( &vlm
->lock
);
2183 int i_connection_count;
2184 int i_connection_active;
2189 vlc_bool_t b_playing;
2190 int i_playing_index;
2193 } vlm_media_status_t;
2197 static vlm_media_sys_t
*vlm_ControlMediaGetById( vlm_t
*p_vlm
, int64_t id
)
2201 for( i
= 0; i
< p_vlm
->i_media
; i
++ )
2203 if( p_vlm
->media
[i
]->cfg
.id
== id
)
2204 return p_vlm
->media
[i
];
2208 static vlm_media_sys_t
*vlm_ControlMediaGetByName( vlm_t
*p_vlm
, const char *psz_name
)
2212 for( i
= 0; i
< p_vlm
->i_media
; i
++ )
2214 if( !strcmp( p_vlm
->media
[i
]->cfg
.psz_name
, psz_name
) )
2215 return p_vlm
->media
[i
];
2219 static int vlm_MediaDescriptionCheck( vlm_t
*p_vlm
, vlm_media_t
*p_cfg
)
2223 if( !p_cfg
|| !p_cfg
->psz_name
||
2224 !strcmp( p_cfg
->psz_name
, "all" ) || !strcmp( p_cfg
->psz_name
, "media" ) || !strcmp( p_cfg
->psz_name
, "schedule" ) )
2225 return VLC_EGENERIC
;
2227 for( i
= 0; i
< p_vlm
->i_media
; i
++ )
2229 if( p_vlm
->media
[i
]->cfg
.id
== p_cfg
->id
)
2231 if( !strcmp( p_vlm
->media
[i
]->cfg
.psz_name
, p_cfg
->psz_name
) )
2232 return VLC_EGENERIC
;
2238 /* Called after a media description is changed/added */
2239 static int vlm_OnMediaUpdate( vlm_t
*p_vlm
, vlm_media_sys_t
*p_media
)
2241 vlm_media_t
*p_cfg
= &p_media
->cfg
;
2242 /* Check if we need to create/delete a vod media */
2245 if( !p_cfg
->b_enabled
&& p_media
->vod
.p_media
)
2247 p_vlm
->p_vod
->pf_media_del( p_vlm
->p_vod
, p_media
->vod
.p_media
);
2248 p_media
->vod
.p_media
= NULL
;
2250 else if( p_cfg
->b_enabled
&& !p_media
->vod
.p_media
&& p_cfg
->i_input
)
2252 /* Pre-parse the input */
2253 input_thread_t
*p_input
;
2259 input_ItemClean( &p_media
->vod
.item
);
2260 input_ItemInit( VLC_OBJECT(p_vlm
), &p_media
->vod
.item
);
2262 if( p_cfg
->psz_output
)
2263 asprintf( &psz_output
, "%s:description", p_cfg
->psz_output
);
2265 asprintf( &psz_output
, "#description" );
2267 p_media
->vod
.item
.psz_uri
= strdup( p_cfg
->ppsz_input
[0] );
2269 TAB_INIT( p_media
->vod
.item
.i_options
, p_media
->vod
.item
.ppsz_options
);
2271 asprintf( &psz_dup
, "sout=%s", psz_output
);
2272 TAB_APPEND( p_media
->vod
.item
.i_options
, p_media
->vod
.item
.ppsz_options
, psz_dup
);
2273 for( i
= 0; i
< p_cfg
->i_option
; i
++ )
2275 psz_dup
= strdup( p_cfg
->ppsz_option
[i
] );
2276 TAB_APPEND( p_media
->vod
.item
.i_options
, p_media
->vod
.item
.ppsz_options
, psz_dup
);
2278 psz_dup
= strdup( "no-sout-keep" );
2279 TAB_APPEND( p_media
->vod
.item
.i_options
, p_media
->vod
.item
.ppsz_options
, psz_dup
);
2281 asprintf( &psz_header
, _("Media: %s"), p_cfg
->psz_name
);
2283 if( (p_input
= input_CreateThreadExtended( p_vlm
, &p_media
->vod
.item
, psz_header
, NULL
) ) )
2285 while( !p_input
->b_eof
&& !p_input
->b_error
)
2288 input_StopThread( p_input
);
2289 input_DestroyThreadExtended( p_input
, NULL
);
2294 if( p_cfg
->vod
.psz_mux
)
2297 es_format_t es
, *p_es
= &es
;
2300 sprintf( fourcc
, "%4.4s", p_cfg
->vod
.psz_mux
);
2301 fourcc
[0] = tolower(fourcc
[0]); fourcc
[1] = tolower(fourcc
[1]);
2302 fourcc
[2] = tolower(fourcc
[2]); fourcc
[3] = tolower(fourcc
[3]);
2304 item
= p_media
->vod
.item
;
2307 es_format_Init( &es
, VIDEO_ES
, *((int *)fourcc
) );
2309 p_media
->vod
.p_media
=
2310 p_vlm
->p_vod
->pf_media_new( p_vlm
->p_vod
, p_cfg
->psz_name
, &item
);
2314 p_media
->vod
.p_media
=
2315 p_vlm
->p_vod
->pf_media_new( p_vlm
->p_vod
, p_cfg
->psz_name
, &p_media
->vod
.item
);
2321 /* TODO start media if needed */
2324 /* TODO add support of var vlm_media_broadcast/vlm_media_vod */
2328 static int vlm_ControlMediaChange( vlm_t
*p_vlm
, vlm_media_t
*p_cfg
)
2330 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, p_cfg
->id
);
2333 if( !p_media
|| vlm_MediaDescriptionCheck( p_vlm
, p_cfg
) )
2334 return VLC_EGENERIC
;
2335 if( ( p_media
->cfg
.b_vod
&& !p_cfg
->b_vod
) || ( !p_media
->cfg
.b_vod
&& p_cfg
->b_vod
) )
2336 return VLC_EGENERIC
;
2340 /* TODO check what are the changes being done (stop instance if needed) */
2343 vlm_media_Clean( &p_media
->cfg
);
2344 vlm_media_Copy( &p_media
->cfg
, p_cfg
);
2346 return vlm_OnMediaUpdate( p_vlm
, p_media
);
2349 static int vlm_ControlMediaAdd( vlm_t
*p_vlm
, vlm_media_t
*p_cfg
, int64_t *p_id
)
2351 vlm_media_sys_t
*p_media
;
2353 if( vlm_MediaDescriptionCheck( p_vlm
, p_cfg
) || vlm_ControlMediaGetByName( p_vlm
, p_cfg
->psz_name
) )
2355 msg_Err( p_vlm
, "invalid media description" );
2356 return VLC_EGENERIC
;
2358 /* Check if we need to load the VOD server */
2359 if( p_cfg
->b_vod
&& !p_vlm
->i_vod
)
2361 p_vlm
->p_vod
= vlc_object_create( p_vlm
, VLC_OBJECT_VOD
);
2362 vlc_object_attach( p_vlm
->p_vod
, p_vlm
);
2363 p_vlm
->p_vod
->p_module
= module_Need( p_vlm
->p_vod
, "vod server", 0, 0 );
2364 if( !p_vlm
->p_vod
->p_module
)
2366 msg_Err( p_vlm
, "cannot find vod server" );
2367 vlc_object_detach( p_vlm
->p_vod
);
2368 vlc_object_release( p_vlm
->p_vod
);
2370 return VLC_EGENERIC
;
2373 p_vlm
->p_vod
->p_data
= p_vlm
;
2374 p_vlm
->p_vod
->pf_media_control
= vlm_MediaVodControl
;
2377 p_media
= malloc( sizeof( vlm_media_sys_t
) );
2380 msg_Err( p_vlm
, "out of memory" );
2383 memset( p_media
, 0, sizeof(vlm_media_sys_t
) );
2388 vlm_media_Copy( &p_media
->cfg
, p_cfg
);
2389 p_media
->cfg
.id
= p_vlm
->i_id
++;
2390 /* FIXME do we do something here if enabled is true ? */
2392 input_ItemInit( VLC_OBJECT(p_vlm
), &p_media
->vod
.item
);
2394 p_media
->vod
.p_media
= NULL
;
2395 TAB_INIT( p_media
->i_instance
, p_media
->instance
);
2398 TAB_APPEND( p_vlm
->i_media
, p_vlm
->media
, p_media
);
2401 *p_id
= p_media
->cfg
.id
;
2403 return vlm_OnMediaUpdate( p_vlm
, p_media
);
2406 static int vlm_ControlMediaDel( vlm_t
*p_vlm
, int64_t id
)
2408 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
2411 return VLC_EGENERIC
;
2413 while( p_media
->i_instance
> 0 )
2414 vlm_ControlInternal( p_vlm
, VLM_STOP_MEDIA_INSTANCE
, id
, p_media
->instance
[0]->psz_name
);
2416 if( p_media
->cfg
.b_vod
)
2418 p_media
->cfg
.b_enabled
= VLC_FALSE
;
2419 vlm_OnMediaUpdate( p_vlm
, p_media
);
2423 vlm_media_Clean( &p_media
->cfg
);
2425 input_ItemClean( &p_media
->vod
.item
);
2427 TAB_REMOVE( p_vlm
->i_media
, p_vlm
->media
, p_media
);
2431 /* Check if we need to unload the VOD server */
2432 if( p_vlm
->p_vod
&& p_vlm
->i_vod
<= 0 )
2434 module_Unneed( p_vlm
->p_vod
, p_vlm
->p_vod
->p_module
);
2435 vlc_object_detach( p_vlm
->p_vod
);
2436 vlc_object_release( p_vlm
->p_vod
);
2437 p_vlm
->p_vod
= NULL
;
2442 static int vlm_ControlMediaGets( vlm_t
*p_vlm
, vlm_media_t
***ppp_dsc
, int *pi_dsc
)
2444 vlm_media_t
**pp_dsc
;
2448 TAB_INIT( i_dsc
, pp_dsc
);
2449 for( i
= 0; i
< p_vlm
->i_media
; i
++ )
2451 vlm_media_t
*p_dsc
= vlm_media_Duplicate( &p_vlm
->media
[i
]->cfg
);
2452 TAB_APPEND( i_dsc
, pp_dsc
, p_dsc
);
2460 static int vlm_ControlMediaClear( vlm_t
*p_vlm
)
2462 while( p_vlm
->i_media
> 0 )
2463 vlm_ControlMediaDel( p_vlm
, p_vlm
->media
[0]->cfg
.id
);
2467 static int vlm_ControlMediaGet( vlm_t
*p_vlm
, int64_t id
, vlm_media_t
**pp_dsc
)
2469 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
2471 return VLC_EGENERIC
;
2473 *pp_dsc
= vlm_media_Duplicate( &p_media
->cfg
);
2476 static int vlm_ControlMediaGetId( vlm_t
*p_vlm
, const char *psz_name
, int64_t *p_id
)
2478 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetByName( p_vlm
, psz_name
);
2480 return VLC_EGENERIC
;
2482 *p_id
= p_media
->cfg
.id
;
2486 static vlm_media_instance_sys_t
*vlm_ControlMediaInstanceGetByName( vlm_media_sys_t
*p_media
, const char *psz_id
)
2490 for( i
= 0; i
< p_media
->i_instance
; i
++ )
2492 const char *psz
= p_media
->instance
[i
]->psz_name
;
2493 if( ( psz
== NULL
&& psz_id
== NULL
) ||
2494 ( psz
&& psz_id
&& !strcmp( psz
, psz_id
) ) )
2495 return p_media
->instance
[i
];
2499 static vlm_media_instance_sys_t
*vlm_MediaInstanceNew( vlm_t
*p_vlm
, const char *psz_name
)
2501 vlm_media_instance_sys_t
*p_instance
= malloc( sizeof(vlm_media_instance_sys_t
) );
2505 memset( p_instance
, 0, sizeof(vlm_media_instance_sys_t
) );
2507 p_instance
->psz_name
= NULL
;
2509 p_instance
->psz_name
= strdup( psz_name
);
2511 input_ItemInit( VLC_OBJECT(p_vlm
), &p_instance
->item
);
2513 p_instance
->i_index
= 0;
2514 p_instance
->b_sout_keep
= VLC_FALSE
;
2515 p_instance
->p_input
= NULL
;
2516 p_instance
->p_sout
= NULL
;
2520 static void vlm_MediaInstanceDelete( vlm_media_instance_sys_t
*p_instance
)
2522 if( p_instance
->p_input
)
2524 input_StopThread( p_instance
->p_input
);
2525 input_DestroyThreadExtended( p_instance
->p_input
, &p_instance
->p_sout
);
2527 if( p_instance
->p_sout
)
2528 sout_DeleteInstance( p_instance
->p_sout
);
2530 input_ItemClean( &p_instance
->item
);
2531 free( p_instance
->psz_name
);
2536 static int vlm_ControlMediaInstanceStart( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
, int i_input_index
, const char *psz_vod_output
)
2538 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
2539 vlm_media_instance_sys_t
*p_instance
;
2542 if( !p_media
|| !p_media
->cfg
.b_enabled
|| p_media
->cfg
.i_input
<= 0 )
2543 return VLC_EGENERIC
;
2545 /* TODO support multiple input for VOD with sout-keep ? */
2547 if( ( p_media
->cfg
.b_vod
&& !psz_vod_output
) || ( !p_media
->cfg
.b_vod
&& psz_vod_output
) )
2548 return VLC_EGENERIC
;
2550 if( i_input_index
< 0 || i_input_index
>= p_media
->cfg
.i_input
)
2551 return VLC_EGENERIC
;
2553 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
2556 vlm_media_t
*p_cfg
= &p_media
->cfg
;
2560 p_instance
= vlm_MediaInstanceNew( p_vlm
, psz_id
);
2564 TAB_INIT( p_instance
->item
.i_options
, p_instance
->item
.ppsz_options
);
2566 if( p_cfg
->psz_output
!= NULL
|| psz_vod_output
!= NULL
)
2569 asprintf( &psz_buffer
, "sout=%s%s%s",
2570 p_cfg
->psz_output
? p_cfg
->psz_output
: "",
2571 (p_cfg
->psz_output
&& psz_vod_output
) ? ":" : psz_vod_output
? "#" : "",
2572 psz_vod_output
? psz_vod_output
: "" );
2573 TAB_APPEND( p_instance
->item
.i_options
, p_instance
->item
.ppsz_options
, psz_buffer
);
2576 for( i
= 0; i
< p_cfg
->i_option
; i
++ )
2578 if( !strcmp( p_cfg
->ppsz_option
[i
], "sout-keep" ) )
2579 p_instance
->b_sout_keep
= VLC_TRUE
;
2580 else if( !strcmp( p_cfg
->ppsz_option
[i
], "nosout-keep" ) || !strcmp( p_cfg
->ppsz_option
[i
], "no-sout-keep" ) )
2581 p_instance
->b_sout_keep
= VLC_FALSE
;
2583 TAB_APPEND( p_instance
->item
.i_options
, p_instance
->item
.ppsz_options
, strdup( p_cfg
->ppsz_option
[i
] ) );
2585 /* We force the right sout-keep value (avoid using the sout-keep from the global configuration)
2586 * FIXME implement input list for VOD (need sout-keep)
2588 if( !p_cfg
->b_vod
&& p_instance
->b_sout_keep
)
2589 psz_keep
= strdup( "sout-keep" );
2591 psz_keep
= strdup( "no-sout-keep" );
2592 TAB_APPEND( p_instance
->item
.i_options
, p_instance
->item
.ppsz_options
, psz_keep
);
2594 TAB_APPEND( p_media
->i_instance
, p_media
->instance
, p_instance
);
2597 /* Stop old instance */
2598 if( p_instance
->p_input
)
2600 if( p_instance
->i_index
== i_input_index
&&
2601 !p_instance
->p_input
->b_eof
&& !p_instance
->p_input
->b_error
)
2603 if( var_GetInteger( p_instance
->p_input
, "state" ) == PAUSE_S
)
2604 var_SetInteger( p_instance
->p_input
, "state", PLAYING_S
);
2608 input_StopThread( p_instance
->p_input
);
2609 input_DestroyThreadExtended( p_instance
->p_input
, &p_instance
->p_sout
);
2610 if( !p_instance
->b_sout_keep
&& p_instance
->p_sout
)
2612 sout_DeleteInstance( p_instance
->p_sout
);
2613 p_instance
->p_sout
= NULL
;
2618 p_instance
->i_index
= i_input_index
;
2619 input_item_SetURI( &p_instance
->item
, p_media
->cfg
.ppsz_input
[p_instance
->i_index
] ) ;
2621 asprintf( &psz_log
, _("Media: %s"), p_media
->cfg
.psz_name
);
2622 p_instance
->p_input
= input_CreateThreadExtended( p_vlm
, &p_instance
->item
, psz_log
, p_instance
->p_sout
);
2623 if( !p_instance
->p_input
)
2625 TAB_REMOVE( p_media
->i_instance
, p_media
->instance
, p_instance
);
2626 vlm_MediaInstanceDelete( p_instance
);
2633 static int vlm_ControlMediaInstanceStop( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
)
2635 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
2636 vlm_media_instance_sys_t
*p_instance
;
2639 return VLC_EGENERIC
;
2641 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
2643 return VLC_EGENERIC
;
2645 TAB_REMOVE( p_media
->i_instance
, p_media
->instance
, p_instance
);
2647 vlm_MediaInstanceDelete( p_instance
);
2651 static int vlm_ControlMediaInstancePause( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
)
2653 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
2654 vlm_media_instance_sys_t
*p_instance
;
2658 return VLC_EGENERIC
;
2660 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
2661 if( !p_instance
|| !p_instance
->p_input
)
2662 return VLC_EGENERIC
;
2664 /* Toggle pause state */
2665 i_state
= var_GetInteger( p_instance
->p_input
, "state" );
2666 if( i_state
== PAUSE_S
)
2667 var_SetInteger( p_instance
->p_input
, "state", PLAYING_S
);
2668 else if( i_state
== PLAYING_S
)
2669 var_SetInteger( p_instance
->p_input
, "state", PAUSE_S
);
2672 static int vlm_ControlMediaInstanceGetTimePosition( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
, int64_t *pi_time
, double *pd_position
)
2674 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
2675 vlm_media_instance_sys_t
*p_instance
;
2678 return VLC_EGENERIC
;
2680 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
2681 if( !p_instance
|| !p_instance
->p_input
)
2682 return VLC_EGENERIC
;
2685 *pi_time
= var_GetTime( p_instance
->p_input
, "time" );
2687 *pd_position
= var_GetFloat( p_instance
->p_input
, "position" );
2690 static int vlm_ControlMediaInstanceSetTimePosition( vlm_t
*p_vlm
, int64_t id
, const char *psz_id
, int64_t i_time
, double d_position
)
2692 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
2693 vlm_media_instance_sys_t
*p_instance
;
2696 return VLC_EGENERIC
;
2698 p_instance
= vlm_ControlMediaInstanceGetByName( p_media
, psz_id
);
2699 if( !p_instance
|| !p_instance
->p_input
)
2700 return VLC_EGENERIC
;
2703 return var_SetTime( p_instance
->p_input
, "time", i_time
);
2704 else if( d_position
>= 0 && d_position
<= 100 )
2705 return var_SetFloat( p_instance
->p_input
, "position", d_position
);
2706 return VLC_EGENERIC
;
2709 static int vlm_ControlMediaInstanceGets( vlm_t
*p_vlm
, int64_t id
, vlm_media_instance_t
***ppp_idsc
, int *pi_instance
)
2711 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
2712 vlm_media_instance_t
**pp_idsc
;
2717 return VLC_EGENERIC
;
2719 TAB_INIT( i_idsc
, pp_idsc
);
2720 for( i
= 0; i
< p_media
->i_instance
; i
++ )
2722 vlm_media_instance_sys_t
*p_instance
= p_media
->instance
[i
];
2723 vlm_media_instance_t
*p_idsc
= vlm_media_instance_New();
2725 if( p_instance
->psz_name
)
2726 p_idsc
->psz_name
= strdup( p_instance
->psz_name
);
2727 if( p_instance
->p_input
)
2729 p_idsc
->i_time
= var_GetTime( p_instance
->p_input
, "time" );
2730 p_idsc
->i_length
= var_GetTime( p_instance
->p_input
, "length" );
2731 p_idsc
->d_position
= var_GetFloat( p_instance
->p_input
, "position" );
2732 if( var_GetInteger( p_instance
->p_input
, "state" ) == PAUSE_S
)
2733 p_idsc
->b_paused
= VLC_TRUE
;
2734 p_idsc
->i_rate
= var_GetInteger( p_instance
->p_input
, "rate" );
2737 TAB_APPEND( i_idsc
, pp_idsc
, p_idsc
);
2739 *ppp_idsc
= pp_idsc
;
2740 *pi_instance
= i_idsc
;
2743 static int vlm_ControlMediaInstanceClear( vlm_t
*p_vlm
, int64_t id
)
2745 vlm_media_sys_t
*p_media
= vlm_ControlMediaGetById( p_vlm
, id
);
2748 return VLC_EGENERIC
;
2750 while( p_media
->i_instance
> 0 )
2751 vlm_ControlMediaInstanceStop( p_vlm
, id
, p_media
->instance
[0]->psz_name
);
2756 static int vlm_ControlScheduleClear( vlm_t
*p_vlm
)
2758 while( p_vlm
->i_schedule
> 0 )
2759 vlm_ScheduleDelete( p_vlm
, p_vlm
->schedule
[0] );
2763 static int vlm_vaControlInternal( vlm_t
*p_vlm
, int i_query
, va_list args
)
2766 vlm_media_t
**pp_dsc
;
2767 vlm_media_t
***ppp_dsc
;
2768 vlm_media_instance_t
***ppp_idsc
;
2770 const char *psz_vod
;
2784 case VLM_GET_MEDIAS
:
2785 ppp_dsc
= (vlm_media_t
***)va_arg( args
, vlm_media_t
*** );
2786 pi_int
= (int *)va_arg( args
, int * );
2787 return vlm_ControlMediaGets( p_vlm
, ppp_dsc
, pi_int
);
2789 case VLM_CLEAR_MEDIAS
:
2790 return vlm_ControlMediaClear( p_vlm
);
2792 case VLM_CHANGE_MEDIA
:
2793 p_dsc
= (vlm_media_t
*)va_arg( args
, vlm_media_t
* );
2794 return vlm_ControlMediaChange( p_vlm
, p_dsc
);
2797 p_dsc
= (vlm_media_t
*)va_arg( args
, vlm_media_t
* );
2798 p_id
= (int64_t*)va_arg( args
, int64_t * );
2799 return vlm_ControlMediaAdd( p_vlm
, p_dsc
, p_id
);
2802 id
= (int64_t)va_arg( args
, int64_t );
2803 return vlm_ControlMediaDel( p_vlm
, id
);
2806 id
= (int64_t)va_arg( args
, int64_t );
2807 pp_dsc
= (vlm_media_t
**)va_arg( args
, vlm_media_t
** );
2808 return vlm_ControlMediaGet( p_vlm
, id
, pp_dsc
);
2810 case VLM_GET_MEDIA_ID
:
2811 psz_id
= (const char*)va_arg( args
, const char * );
2812 p_id
= (int64_t*)va_arg( args
, int64_t * );
2813 return vlm_ControlMediaGetId( p_vlm
, psz_id
, p_id
);
2816 /* Media instance control */
2817 case VLM_GET_MEDIA_INSTANCES
:
2818 id
= (int64_t)va_arg( args
, int64_t );
2819 ppp_idsc
= (vlm_media_instance_t
***)va_arg( args
, vlm_media_instance_t
*** );
2820 pi_int
= (int *)va_arg( args
, int *);
2821 return vlm_ControlMediaInstanceGets( p_vlm
, id
, ppp_idsc
, pi_int
);
2823 case VLM_CLEAR_MEDIA_INSTANCES
:
2824 id
= (int64_t)va_arg( args
, int64_t );
2825 return vlm_ControlMediaInstanceClear( p_vlm
, id
);
2828 case VLM_START_MEDIA_BROADCAST_INSTANCE
:
2829 id
= (int64_t)va_arg( args
, int64_t );
2830 psz_id
= (const char*)va_arg( args
, const char* );
2831 i_int
= (int)va_arg( args
, int );
2832 return vlm_ControlMediaInstanceStart( p_vlm
, id
, psz_id
, i_int
, NULL
);
2834 case VLM_START_MEDIA_VOD_INSTANCE
:
2835 id
= (int64_t)va_arg( args
, int64_t );
2836 psz_id
= (const char*)va_arg( args
, const char* );
2837 i_int
= (int)va_arg( args
, int );
2838 psz_vod
= (const char*)va_arg( args
, const char* );
2840 return VLC_EGENERIC
;
2841 return vlm_ControlMediaInstanceStart( p_vlm
, id
, psz_id
, i_int
, psz_vod
);
2843 case VLM_STOP_MEDIA_INSTANCE
:
2844 id
= (int64_t)va_arg( args
, int64_t );
2845 psz_id
= (const char*)va_arg( args
, const char* );
2846 return vlm_ControlMediaInstanceStop( p_vlm
, id
, psz_id
);
2848 case VLM_PAUSE_MEDIA_INSTANCE
:
2849 id
= (int64_t)va_arg( args
, int64_t );
2850 psz_id
= (const char*)va_arg( args
, const char* );
2851 return vlm_ControlMediaInstancePause( p_vlm
, id
, psz_id
);
2853 case VLM_GET_MEDIA_INSTANCE_TIME
:
2854 id
= (int64_t)va_arg( args
, int64_t );
2855 psz_id
= (const char*)va_arg( args
, const char* );
2856 pi_i64
= (int64_t*)va_arg( args
, int64_t * );
2857 return vlm_ControlMediaInstanceGetTimePosition( p_vlm
, id
, psz_id
, pi_i64
, NULL
);
2858 case VLM_GET_MEDIA_INSTANCE_POSITION
:
2859 id
= (int64_t)va_arg( args
, int64_t );
2860 psz_id
= (const char*)va_arg( args
, const char* );
2861 pd_double
= (double*)va_arg( args
, double* );
2862 return vlm_ControlMediaInstanceGetTimePosition( p_vlm
, id
, psz_id
, NULL
, pd_double
);
2864 case VLM_SET_MEDIA_INSTANCE_TIME
:
2865 id
= (int64_t)va_arg( args
, int64_t );
2866 psz_id
= (const char*)va_arg( args
, const char* );
2867 i_i64
= (int64_t)va_arg( args
, int64_t);
2868 return vlm_ControlMediaInstanceSetTimePosition( p_vlm
, id
, psz_id
, i_i64
, -1 );
2869 case VLM_SET_MEDIA_INSTANCE_POSITION
:
2870 id
= (int64_t)va_arg( args
, int64_t );
2871 psz_id
= (const char*)va_arg( args
, const char* );
2872 d_double
= (double)va_arg( args
, double );
2873 return vlm_ControlMediaInstanceSetTimePosition( p_vlm
, id
, psz_id
, -1, d_double
);
2875 case VLM_CLEAR_SCHEDULES
:
2876 return vlm_ControlScheduleClear( p_vlm
);
2879 msg_Err( p_vlm
, "unknown VLM query" );
2880 return VLC_EGENERIC
;
2883 static int vlm_ControlInternal( vlm_t
*p_vlm
, int i_query
, ... )
2888 va_start( args
, i_query
);
2889 i_result
= vlm_vaControlInternal( p_vlm
, i_query
, args
);
2895 int vlm_Control( vlm_t
*p_vlm
, int i_query
, ... )
2900 va_start( args
, i_query
);
2902 vlc_mutex_lock( &p_vlm
->lock
);
2903 i_result
= vlm_vaControlInternal( p_vlm
, i_query
, args
);
2904 vlc_mutex_unlock( &p_vlm
->lock
);
2911 #else /* ENABLE_VLM */
2913 /* We just define an empty wrapper */
2914 vlm_t
*__vlm_New( vlc_object_t
*a
)
2916 msg_Err( a
, "VideoLAN manager support is disabled" );
2920 void vlm_Delete( vlm_t
*a
)
2925 int vlm_ExecuteCommand( vlm_t
*a
, const char *b
, vlm_message_t
**c
)
2930 vlm_message_t
*vlm_MessageNew( const char *psz_name
,
2931 const char *psz_format
, ... )
2933 (void)psz_name
; (void)psz_format
;
2937 vlm_message_t
*vlm_MessageAdd( vlm_message_t
*p_message
,
2938 vlm_message_t
*p_child
)
2943 void vlm_MessageDelete( vlm_message_t
*a
)
2948 int vlm_Control( vlm_t
*p_vlm
, int i_query
, ... )
2950 (void)p_vlm
; (void)i_query
;
2951 return VLC_EGENERIC
;
2954 #endif /* ENABLE_VLM */