1 /*****************************************************************************
2 * vlm.c: VLM interface plugin
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
7 * Authors: Simon Latapie <garf@videolan.org>
8 * Laurent Aimar <fenrir@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 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 General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
28 #include <stdlib.h> /* malloc(), free() */
33 #include <vlc/input.h>
36 # include <time.h> /* ctime() */
41 /*****************************************************************************
43 *****************************************************************************/
44 static char *vlm_Save( vlm_t * );
45 static int vlm_Load( vlm_t *, char *);
46 static vlm_media_t *vlm_MediaNew( vlm_t *, char *, int );
47 static int vlm_MediaDelete( vlm_t *, vlm_media_t *, char * );
48 static vlm_media_t *vlm_MediaSearch( vlm_t *, char * );
49 static int vlm_MediaSetup( vlm_media_t *, char *, char * );
50 static int vlm_MediaControl( vlm_t *, vlm_media_t *, char *, char * );
51 static vlm_message_t *vlm_Show( vlm_t *, vlm_media_t *, vlm_schedule_t *, char * );
52 static vlm_message_t *vlm_Help( vlm_t *, char * );
54 static vlm_message_t* vlm_MessageNew( char * , char * );
55 static vlm_message_t* vlm_MessageAdd( vlm_message_t*, vlm_message_t* );
57 static vlm_schedule_t *vlm_ScheduleNew( vlm_t *, char *);
58 static int vlm_ScheduleDelete( vlm_t *, vlm_schedule_t *, char *);
59 static int vlm_ScheduleSetup( vlm_schedule_t *, char *, char *);
60 static vlm_schedule_t *vlm_ScheduleSearch( vlm_t *, char *);
62 static int ExecuteCommand( vlm_t *, char * , vlm_message_t **);
64 static int Manage( vlc_object_t* );
67 static char *FindEndCommand( char *psz )
77 while( ( *s_sent != '\"' ) && ( *s_sent != '\0' ) )
81 s_sent = FindEndCommand( s_sent );
99 else /* *s_sent == '\0' , which means the number of " is incorrect */
109 while( ( *s_sent != '\'' ) && ( *s_sent != '\0' ) )
111 if( *s_sent == '\"' )
113 s_sent = FindEndCommand( s_sent );
126 if( *s_sent == '\'' )
131 else /* *s_sent == '\0' , which means the number of ' is incorrect */
137 default: /* now we can look for spaces */
139 while( ( *s_sent != ' ' ) && ( *s_sent != '\0' ) )
141 if( ( *s_sent == '\'' ) || ( *s_sent == '\"' ) )
143 s_sent = FindEndCommand( s_sent );
155 static char *FindEndCommand( char *psz )
160 *psz != ' ' && *psz != '\t' &&
161 *psz != '\n' && *psz != '\r' )
163 if( *psz == '\'' || *psz == '"' )
167 while( *psz && *psz != d && *psz != *psz != '\n' && *psz != '\r' )
169 if( ( d == '\'' && *psz == '"' ) ||
170 ( d == '"' && *psz == '\'' ) )
172 psz = FindEndCommand( psz );
186 int vlm_ExecuteCommand( vlm_t *vlm, char *command, vlm_message_t **message)
190 vlc_mutex_lock( &vlm->lock );
191 result = ExecuteCommand( vlm, command, message );
192 vlc_mutex_unlock( &vlm->lock );
197 /* Execute a command which ends by '\0' (string) */
198 int ExecuteCommand( vlm_t *vlm, char *command , vlm_message_t **p_message)
202 char **p_command = NULL;
205 vlm_message_t * message = NULL;
207 /* First, parse the line and cut it */
208 while( *cmd != '\0' )
220 p_temp = FindEndCommand( cmd );
228 i_temp = p_temp - cmd;
230 p_command = realloc( p_command , (i_command + 1) * sizeof( char* ) );
231 p_command[ i_command ] = malloc( (i_temp + 1) * sizeof( char ) ); // don't forget the '\0'
232 strncpy( p_command[ i_command ] , cmd , i_temp );
233 (p_command[ i_command ])[ i_temp ] = '\0';
240 /* And then Interpret it */
244 message = vlm_MessageNew( "" , NULL );
249 if( strcmp(p_command[0] , "segfault") == 0 )
251 /* the only command we really need */
254 else if( strcmp(p_command[0] , "new") == 0 )
260 vlm_schedule_t *schedule;
262 if( strcmp(p_command[2] , "schedule") == 0 )
264 /* new vlm_schedule */
265 if( vlm_ScheduleSearch( vlm , p_command[1] ) != NULL || strcmp(p_command[1] , "schedule") == 0 )
267 char *error_message = malloc( strlen(p_command[1]) + strlen(" is already used") + 1 );
268 sprintf( error_message, "%s is already used" , p_command[1] );
269 message = vlm_MessageNew( "new" , error_message );
270 free( error_message );
275 schedule = vlm_ScheduleNew( vlm , p_command[1] );
278 if( i_command > 3 ) // hey, there are properties
280 for( i = 3 ; i < i_command ; i++ )
282 if( strcmp( p_command[i] , "enabled" ) == 0 || strcmp( p_command[i] , "disabled" ) == 0 )
284 vlm_ScheduleSetup( schedule, p_command[i], NULL );
286 /* Beware: evrything behind append is considered as command line */
287 else if( strcmp( p_command[i] , "append" ) == 0 )
294 for( j = (i + 1); j < i_command; j++ )
296 p_command[i] = realloc( p_command[i], strlen(p_command[i]) + strlen(p_command[j]) + 1 + 1);
297 strcat( p_command[i], " " );
298 strcat( p_command[i], p_command[j] );
301 vlm_ScheduleSetup( schedule, p_command[i - 1], p_command[i] );
307 if( (i+1) < i_command )
309 vlm_ScheduleSetup( schedule, p_command[i], p_command[i+1] );
314 vlm_ScheduleDelete( vlm, schedule, NULL );
315 message = vlm_MessageNew( p_command[i], "Wrong properties syntax" );
322 message = vlm_MessageNew( "new" , NULL );
327 message = vlm_MessageNew( "new" , NULL );
332 if( strcmp(p_command[2] , "vod") == 0 )
336 else if( strcmp(p_command[2] , "broadcast") == 0 )
338 i_type = BROADCAST_TYPE;
342 char *error_message = malloc( strlen(p_command[1]) + strlen(": Choose between vod or broadcast") + 1 );
343 sprintf( error_message, "%s: Choose between vod or broadcast" , p_command[1] );
344 message = vlm_MessageNew( "new" , error_message );
345 free( error_message );
351 if( vlm_MediaSearch( vlm , p_command[1] ) != NULL || strcmp(p_command[1] , "media") == 0 )
353 char *error_message = malloc( strlen(p_command[1]) + strlen(" is already used") + 1 );
354 sprintf( error_message, "%s is already used" , p_command[1] );
355 message = vlm_MessageNew( "new" , error_message );
356 free( error_message );
361 media = vlm_MediaNew( vlm , p_command[1] , i_type );
363 if( i_command > 3 ) // hey, there are properties
365 for( i = 3 ; i < i_command ; i++ )
367 if( strcmp( p_command[i] , "enabled" ) == 0 || strcmp( p_command[i] , "disabled" ) == 0 )
369 vlm_MediaSetup( media, p_command[i], NULL );
373 if( (i+1) < i_command )
375 vlm_MediaSetup( media, p_command[i], p_command[i+1] );
380 vlm_MediaDelete( vlm, media, NULL );
381 message = vlm_MessageNew( p_command[i] , "Wrong properties syntax" );
388 message = vlm_MessageNew( "new" , NULL );
393 message = vlm_MessageNew( "new" , NULL );
399 message = vlm_MessageNew( "new" , "Wrong command syntax" );
404 else if( strcmp(p_command[0] , "del") == 0 )
409 vlm_schedule_t *schedule;
411 media = vlm_MediaSearch( vlm , p_command[1] );
412 schedule = vlm_ScheduleSearch( vlm , p_command[1] );
414 if( schedule != NULL )
416 vlm_ScheduleDelete( vlm, schedule, NULL );
417 message = vlm_MessageNew( "del" , NULL );
421 else if( media != NULL )
423 vlm_MediaDelete( vlm, media, NULL );
424 message = vlm_MessageNew( "del" , NULL );
428 else if( strcmp(p_command[1] , "media") == 0 )
430 for( i = 0; i < vlm->i_media; i++ )
432 vlm_MediaDelete( vlm, vlm->media[i], NULL );
435 else if( strcmp(p_command[1] , "schedule") == 0 )
437 for( i = 0; i < vlm->i_schedule; i++ )
439 vlm_ScheduleDelete( vlm, vlm->schedule[i], NULL );
442 else if( strcmp(p_command[1] , "all") == 0 )
444 for( i = 0; i < vlm->i_media; i++ )
446 vlm_MediaDelete( vlm, vlm->media[i], NULL );
449 for( i = 0; i < vlm->i_schedule; i++ )
451 vlm_ScheduleDelete( vlm, vlm->schedule[i], NULL );
456 char *error_message = malloc( strlen(p_command[1]) + strlen(": media unknown") + 1 );
457 sprintf( error_message, "%s: media unknown" , p_command[1] );
458 message = vlm_MessageNew( "del" , error_message );
459 free( error_message );
466 message = vlm_MessageNew( "setup" , "Wrong command syntax" );
471 else if( strcmp(p_command[0] , "show") == 0 )
475 message = vlm_Show( vlm, NULL , NULL, NULL );
479 else if( i_command == 2 )
482 vlm_schedule_t *schedule;
484 media = vlm_MediaSearch( vlm , p_command[1] );
485 schedule = vlm_ScheduleSearch( vlm , p_command[1] );
487 if( schedule != NULL )
489 message = vlm_Show( vlm, NULL, schedule, NULL );
491 else if( media != NULL )
493 message = vlm_Show( vlm, media, NULL, NULL );
497 message = vlm_Show( vlm, NULL, NULL, p_command[1] );
505 message = vlm_MessageNew( "show" , "Wrong command syntax" );
510 else if( strcmp(p_command[0] , "help") == 0 )
514 message = vlm_Help( vlm, NULL );
520 message = vlm_MessageNew( "help" , "Wrong command syntax" );
525 else if( strcmp(p_command[0] , "setup") == 0 )
530 vlm_schedule_t *schedule;
532 media = vlm_MediaSearch( vlm , p_command[1] );
533 schedule = vlm_ScheduleSearch( vlm , p_command[1] );
535 if( schedule != NULL )
537 for( i = 2 ; i < i_command ; i++ )
539 if( strcmp( p_command[i] , "enabled" ) == 0 || strcmp( p_command[i] , "disabled" ) == 0 )
541 vlm_ScheduleSetup( schedule, p_command[i], NULL );
543 /* Beware: evrything behind append is considered as command line */
544 else if( strcmp( p_command[i] , "append" ) == 0 )
551 for( j = (i + 1); j < i_command; j++ )
553 p_command[i] = realloc( p_command[i], strlen(p_command[i]) + strlen(p_command[j]) + 1 + 1);
554 strcat( p_command[i], " " );
555 strcat( p_command[i], p_command[j] );
558 vlm_ScheduleSetup( schedule, p_command[i - 1], p_command[i] );
564 if( (i+1) < i_command )
566 vlm_ScheduleSetup( schedule, p_command[i], p_command[i+1] );
571 vlm_ScheduleDelete( vlm, schedule, NULL );
572 message = vlm_MessageNew( "setup" , "Wrong properties syntax" );
579 message = vlm_MessageNew( "setup" , NULL );
583 else if( media != NULL )
585 for( i = 2 ; i < i_command ; i++ )
587 if( strcmp( p_command[i] , "enabled" ) == 0 || strcmp( p_command[i] , "disabled" ) == 0 )
588 { /* only one argument */
589 vlm_MediaSetup( media, p_command[i], NULL );
591 else if( strcmp( p_command[i] , "loop" ) == 0 || strcmp( p_command[i] , "unloop" ) == 0 )
593 if( media->i_type != BROADCAST_TYPE )
595 message = vlm_MessageNew( "setup" , "lool only available for broadcast" );
601 vlm_MediaSetup( media, p_command[i], NULL );
606 if( (i+1) < i_command )
608 vlm_MediaSetup( media, p_command[i], p_command[i+1] );
613 vlm_MediaDelete( vlm, media, NULL );
614 message = vlm_MessageNew( "setup" , "Wrong properties syntax" );
621 message = vlm_MessageNew( "setup" , NULL );
627 char *error_message = malloc( strlen(p_command[1]) + strlen(" unknown") + 1 );
628 sprintf( error_message, "%s unknown" , p_command[1] );
629 message = vlm_MessageNew( "setup" , error_message );
630 free( error_message );
638 message = vlm_MessageNew( "setup" , "Wrong command syntax" );
643 else if( strcmp(p_command[0] , "control") == 0 )
650 media = vlm_MediaSearch( vlm , p_command[1] );
654 char *error_message = malloc( strlen(p_command[1]) + strlen(": media unknown") + 1 );
655 sprintf( error_message, "%s: media unknown" , p_command[1] );
656 message = vlm_MessageNew( "control" , error_message );
657 free( error_message );
667 psz_args = p_command[3];
675 vlm_MediaControl( vlm, media, p_command[2], psz_args );
676 message = vlm_MessageNew( "control" , NULL );
683 message = vlm_MessageNew( "control" , "Wrong command syntax" );
688 else if( strcmp(p_command[0] , "save") == 0 )
695 file = fopen( p_command[1], "w" );
699 message = vlm_MessageNew( "save" , "Unable to save file" );
707 save = vlm_Save( vlm );
709 fwrite( save, strlen( save ) , 1 , file );
712 message = vlm_MessageNew( "save" , NULL );
719 message = vlm_MessageNew( "save" , "Wrong command" );
724 else if( strcmp(p_command[0] , "load") == 0 )
731 file = fopen( p_command[1], "r" );
735 message = vlm_MessageNew( "load" , "Unable to load file" );
744 if( fseek( file, 0, SEEK_END) == 0 )
746 size = ftell( file );
747 fseek( file, 0, SEEK_SET);
748 buffer = malloc( size + 1 );
749 fread( buffer, 1, size, file);
750 buffer[ size ] = '\0';
751 if( vlm_Load( vlm, buffer ) )
754 message = vlm_MessageNew( "load" , "error while loading file" );
762 message = vlm_MessageNew( "load" , "read file error" );
767 message = vlm_MessageNew( "load" , NULL );
774 message = vlm_MessageNew( "load" , "Wrong command" );
781 message = vlm_MessageNew( p_command[0] , "Unknown comand" );
788 for( i = 0 ; i < i_command ; i++ )
790 free( p_command[i] );
793 *p_message = message;
799 static vlm_media_t *vlm_MediaSearch( vlm_t *vlm, char *psz_name )
803 for( i = 0; i < vlm->i_media; i++ )
805 if( strcmp( psz_name, vlm->media[i]->psz_name ) == 0 )
807 return vlm->media[i];
815 static vlm_media_t *vlm_MediaNew( vlm_t *vlm , char *psz_name, int i_type )
817 vlm_media_t *media= malloc( sizeof( vlm_media_t ));
819 media->psz_name = strdup( psz_name );
820 media->b_enabled = VLC_FALSE;
821 media->b_loop = VLC_FALSE;
825 media->psz_output = NULL;
827 media->option = NULL;
828 media->i_input_option = 0;
829 media->input_option = NULL;
830 media->i_type = i_type;
831 media->p_input = NULL;
833 TAB_APPEND( vlm->i_media , vlm->media , media );
839 /* for now, simple delete. After, del with options (last arg) */
840 static int vlm_MediaDelete( vlm_t *vlm, vlm_media_t *media, char *psz_name )
851 input_StopThread( media->p_input );
853 input_DestroyThread( media->p_input );
854 vlc_object_detach( media->p_input );
855 vlc_object_destroy( media->p_input );
858 TAB_REMOVE( vlm->i_media, vlm->media , media );
860 if( vlm->i_media == 0 && vlm->media ) free( vlm->media );
862 free( media->psz_name );
864 for( i = 0; i < media->i_input; i++ )
866 free( media->input[i] );
868 if( media->input ) free( media->input );
870 if( media->psz_output ) free( media->psz_output );
872 for( i = 0; i < media->i_option; i++ )
874 free( media->option[i] );
876 if(media->option) free( media->option );
878 for( i = 0; i < media->i_input_option; i++ )
880 free( media->input_option[i] );
882 if( media->input_option ) free( media->input_option );
890 static int vlm_MediaSetup( vlm_media_t *media, char *psz_cmd, char *psz_value )
892 if( strcmp( psz_cmd, "loop" ) == 0 )
894 media->b_loop = VLC_TRUE;
896 else if( strcmp( psz_cmd, "unloop" ) == 0 )
898 media->b_loop = VLC_FALSE;
900 else if( strcmp( psz_cmd, "enabled" ) == 0 )
902 media->b_enabled = VLC_TRUE;
904 else if( strcmp( psz_cmd, "disabled" ) == 0 )
906 media->b_enabled = VLC_FALSE;
908 else if( strcmp( psz_cmd, "input" ) == 0 )
912 if( psz_value != NULL && strlen(psz_value) > 1 && ( psz_value[0] == '\'' || psz_value[0] == '\"' )
913 && ( psz_value[ strlen(psz_value) - 1 ] == '\'' || psz_value[ strlen(psz_value) - 1 ] == '\"' ) )
915 input = malloc( strlen(psz_value) - 1 );
917 memcpy( input , psz_value + 1 , strlen(psz_value) - 2 );
918 input[ strlen(psz_value) - 2 ] = '\0';
922 input = strdup( psz_value );
925 TAB_APPEND( media->i_input, media->input, input );
927 else if( strcmp( psz_cmd, "output" ) == 0 )
929 if( media->psz_output != NULL )
931 free( media->psz_output );
933 media->psz_output = strdup( psz_value );
935 else if( strcmp( psz_cmd, "option" ) == 0 )
938 option = strdup( psz_value );
940 TAB_APPEND( media->i_option, media->option, option );
949 static int vlm_MediaControl( vlm_t *vlm, vlm_media_t *media, char *psz_name, char *psz_args )
951 if( strcmp( psz_name, "play" ) == 0 )
955 if( media->b_enabled == VLC_TRUE )
957 if( psz_args != NULL && sscanf( psz_args, "%d", &i ) == 1 && i < media->i_input )
966 if( media->psz_output != NULL )
968 media->input_option = malloc( sizeof( char* ) );
969 media->input_option[0] = malloc( strlen(media->psz_output) + 1 + 6 );
970 sprintf( media->input_option[0], ":sout=%s" , media->psz_output );
971 media->i_input_option = 1;
975 media->input_option = NULL;
976 media->i_input_option = 0;
979 for( i=0 ; i < media->i_option ; i++ )
981 media->i_input_option++;
982 media->input_option = realloc( media->input_option, (media->i_input_option) * sizeof( char* ) );
983 media->input_option[ media->i_input_option - 1 ] = malloc( strlen(media->option[i]) + 1 + 1 );
984 sprintf( media->input_option[ media->i_input_option - 1 ], ":%s" , media->option[i] );
987 media->p_input = input_CreateThread( vlm, media->input[media->i_index], media->input_option, media->i_input_option );
996 else if( strcmp( psz_name, "seek" ) == 0 )
1001 if( psz_args && sscanf( psz_args, "%f", &f_percentage ) == 1 )
1003 val.f_float = f_percentage / 100.0 ;
1004 var_Set( media->p_input, "position", val );
1008 else if( strcmp( psz_name, "stop" ) == 0 )
1012 if( media->p_input )
1014 input_StopThread( media->p_input );
1015 input_DestroyThread( media->p_input );
1016 vlc_object_detach( media->p_input );
1017 vlc_object_destroy( media->p_input );
1018 media->p_input = NULL;
1020 for( i=0 ; i < media->i_input_option ; i++ )
1022 free( media->input_option[i] );
1024 if( media->input_option) free( media->input_option );
1026 media->input_option = NULL;
1027 media->i_input_option = 0;
1032 else if( strcmp( psz_name, "pause" ) == 0 )
1038 if( media->p_input != NULL )
1040 var_Get( media->p_input, "state", &val );
1043 if( val.i_int == PAUSE_S )
1045 if( media->p_input )
1047 val.i_int = PLAYING_S;
1048 var_Set( media->p_input, "state", val );
1053 if( media->p_input )
1055 val.i_int = PAUSE_S;
1056 var_Set( media->p_input, "state", val );
1065 static vlm_message_t *vlm_Show( vlm_t *vlm, vlm_media_t *media, vlm_schedule_t *schedule, char *psz_filter )
1071 vlm_message_t *message;
1072 vlm_message_t *message_media;
1073 vlm_message_t *message_child;
1075 message = vlm_MessageNew( "show" , NULL );
1076 message_media = vlm_MessageAdd( message , vlm_MessageNew( media->psz_name , NULL ) );
1078 if( media->i_type == VOD_TYPE )
1080 vlm_MessageAdd( message_media , vlm_MessageNew( "type" , "vod" ) );
1084 vlm_MessageAdd( message_media , vlm_MessageNew( "type" , "broadcast" ) );
1087 if( media->b_enabled == VLC_TRUE )
1089 vlm_MessageAdd( message_media , vlm_MessageNew( "enabled" , "yes" ) );
1093 vlm_MessageAdd( message_media , vlm_MessageNew( "enabled" , "no" ) );
1096 if( media->b_loop == VLC_TRUE )
1098 vlm_MessageAdd( message_media , vlm_MessageNew( "loop" , "yes" ) );
1101 message_child = vlm_MessageAdd( message_media , vlm_MessageNew( "inputs" , NULL ) );
1103 for( i=0 ; i < (media->i_input) ; i++ )
1105 vlm_MessageAdd( message_child , vlm_MessageNew( media->input[i] , NULL ) );
1108 if( media->psz_output != NULL )
1110 vlm_MessageAdd( message_media , vlm_MessageNew( "output" , media->psz_output ) );
1113 message_child = vlm_MessageAdd( message_media , vlm_MessageNew( "options" , NULL ) );
1115 for( i=0 ; i < (media->i_option) ; i++ )
1117 vlm_MessageAdd( message_child , vlm_MessageNew( media->option[i] , NULL ) );
1120 if( media->p_input != NULL )
1124 var_Get( media->p_input, "state", &val );
1126 if( val.i_int == PLAYING_S )
1128 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "playing" ) );
1130 else if( val.i_int == PAUSE_S )
1132 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "paused" ) );
1136 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "stop" ) );
1141 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "stop" ) );
1147 else if( schedule != NULL )
1150 vlm_message_t *message;
1151 vlm_message_t *message_schedule;
1152 vlm_message_t *message_child;
1154 message = vlm_MessageNew( "show" , NULL );
1155 message_schedule = vlm_MessageAdd( message , vlm_MessageNew( schedule->psz_name , NULL ) );
1157 vlm_MessageAdd( message_schedule , vlm_MessageNew( "type" , "schedule" ) );
1159 if( schedule->b_enabled == VLC_TRUE )
1161 vlm_MessageAdd( message_schedule , vlm_MessageNew( "enabled" , "yes" ) );
1165 vlm_MessageAdd( message_schedule , vlm_MessageNew( "enabled" , "no" ) );
1168 if( schedule->i_date != 0 )
1170 time_t i_time = schedule->i_date / (int64_t)1000000;
1174 ctime_r( &i_time, psz_date );
1176 char *psz_date = ctime( &i_time );
1178 vlm_MessageAdd( message_schedule , vlm_MessageNew( "date" , psz_date ) );
1182 vlm_MessageAdd( message_schedule , vlm_MessageNew( "date" , "now" ) );
1185 if( schedule->i_period != 0 )
1188 time_t i_time = (time_t) ( schedule->i_period / 1000000 );
1191 date.tm_sec = (int)( i_time % 60 );
1192 i_time = i_time / 60;
1193 date.tm_min = (int)( i_time % 60 );
1194 i_time = i_time / 60;
1195 date.tm_hour = (int)( i_time % 24 );
1196 i_time = i_time / 24;
1197 date.tm_mday = (int)( i_time % 30 );
1198 i_time = i_time / 30;
1199 /* okay, okay, months are not always 30 days long */
1200 date.tm_mon = (int)( i_time % 12 );
1201 i_time = i_time / 12;
1202 date.tm_year = (int)i_time;
1204 sprintf( buffer, "%d years %d months %d days %d hours %d minutes %d seconds", date.tm_year ,
1211 vlm_MessageAdd( message_schedule , vlm_MessageNew( "period" , buffer ) );
1213 if( schedule->i_repeat >= 0 )
1215 sprintf( buffer, "%d" , schedule->i_repeat );
1216 vlm_MessageAdd( message_schedule , vlm_MessageNew( "repeat" , buffer ) );
1220 message_child = vlm_MessageAdd( message_schedule , vlm_MessageNew( "commands" , NULL ) );
1222 for( i=0 ; i < (schedule->i_command) ; i++ )
1224 vlm_MessageAdd( message_child , vlm_MessageNew( schedule->command[i] , NULL ) );
1230 else if( psz_filter && strcmp( psz_filter , "media") == 0 )
1233 vlm_message_t *message;
1234 vlm_message_t *message_child;
1236 message = vlm_MessageNew( "show" , NULL );
1237 message_child = vlm_MessageAdd( message , vlm_MessageNew( "media" , NULL ) );
1239 for( i = 0; i < vlm->i_media; i++ )
1241 vlm_media_t *m = vlm->media[i];
1242 vlm_message_t *message_media = vlm_MessageAdd( message_child , vlm_MessageNew( m->psz_name , NULL ) );
1244 if( m->i_type == VOD_TYPE )
1246 vlm_MessageAdd( message_media , vlm_MessageNew( "type" , "vod" ) );
1250 vlm_MessageAdd( message_media , vlm_MessageNew( "type" , "broadcast" ) );
1253 if( m->b_enabled == VLC_TRUE )
1255 vlm_MessageAdd( message_media , vlm_MessageNew( "enabled" , "yes" ) );
1259 vlm_MessageAdd( message_media , vlm_MessageNew( "enabled" , "no" ) );
1262 if( m->p_input != NULL )
1266 var_Get( m->p_input, "state", &val );
1268 if( val.i_int == PLAYING_S )
1270 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "playing" ) );
1272 else if( val.i_int == PAUSE_S )
1274 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "paused" ) );
1278 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "stop" ) );
1283 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "stop" ) );
1289 else if( psz_filter && strcmp( psz_filter , "schedule") == 0 )
1292 vlm_message_t *message;
1293 vlm_message_t *message_child;
1295 message = vlm_MessageNew( "show" , NULL );
1296 message_child = vlm_MessageAdd( message , vlm_MessageNew( "schedule" , NULL ) );
1298 for( i = 0; i < vlm->i_schedule; i++ )
1300 vlm_schedule_t *s = vlm->schedule[i];
1301 vlm_message_t *message_schedule = vlm_MessageAdd( message_child , vlm_MessageNew( s->psz_name , NULL ) );
1303 if( s->b_enabled == VLC_TRUE )
1306 mtime_t i_next_date;
1308 vlm_MessageAdd( message_schedule , vlm_MessageNew( "enabled" , "yes" ) );
1310 /* calculate next date */
1313 i_next_date = s->i_date;
1315 if( s->i_period != 0 )
1318 while( s->i_date + j * s->i_period <= i_time && s->i_repeat > j )
1323 i_next_date = s->i_date + j * s->i_period;
1326 if( i_next_date > i_time )
1328 time_t i_date = (time_t) (i_next_date / 1000000) ;
1332 ctime_r( &i_date, psz_date );
1334 char *psz_date = ctime( &i_date );
1337 vlm_MessageAdd( message_schedule , vlm_MessageNew( "next launch" , psz_date ) );
1342 vlm_MessageAdd( message_schedule , vlm_MessageNew( "enabled" , "no" ) );
1348 else if( psz_filter == NULL && media == NULL && schedule == NULL )
1350 vlm_message_t *show1 = vlm_Show( vlm, NULL, NULL, "media" );
1351 vlm_message_t *show2 = vlm_Show( vlm, NULL, NULL, "schedule" );
1353 vlm_MessageAdd( show1 , show2->child[0] );
1355 /* we must destroy the parent node "show" of show2, and not the children */
1356 free( show2->psz_name );
1363 return vlm_MessageNew( "show" , NULL );
1367 static vlm_message_t *vlm_Help( vlm_t *vlm, char *psz_filter )
1369 vlm_message_t *message;
1371 if( psz_filter == NULL )
1373 char *help = malloc( strlen( "Commands Syntax:" ) +
1374 strlen( "\n new (name) vod|broadcast|schedule [properties]" ) +
1375 strlen( "\n setup (name) (properties)" ) +
1376 strlen( "\n show [(name)|media|schedule]" ) +
1377 strlen( "\n del (name)|all|media|schedule" ) +
1378 strlen( "\n control (name) (command)" ) +
1379 strlen( "\n save (config_file)" ) +
1380 strlen( "\n load (config_file)" ) +
1381 strlen( "\nMedia Proprieties Syntax:" ) +
1382 strlen( "\n input (input_name)" ) +
1383 strlen( "\n output (output_name)" ) +
1384 strlen( "\n option (option_name)[=value]" ) +
1385 strlen( "\n enabled|disabled" ) +
1386 strlen( "\n loop|unloop (broadcast only)" ) +
1387 strlen( "\nSchedule Proprieties Syntax:" ) +
1388 strlen( "\n enabled|disabled" ) +
1389 strlen( "\n append (command_until_rest_of_the_line)" ) +
1390 strlen( "\n date (year)/(month)/(day)-(hour):(minutes):(seconds)|now" ) +
1391 strlen( "\n period (years_aka_12_months)/(months_aka_30_days)/(days)-(hours):(minutes):(seconds)" ) +
1392 strlen( "\n repeat (number_of_repetitions)" ) +
1393 strlen( "\nControl Commands Syntax:" ) +
1394 strlen( "\n play\n pause\n stop\n seek (percentage)\n" ) + 1 );
1398 "\n new (name) vod|broadcast|schedule [properties]"
1399 "\n setup (name) (properties)"
1400 "\n show [(name)|media|schedule]"
1401 "\n del (name)|all|media|schedule"
1402 "\n control (name) (command)"
1403 "\n save (config_file)"
1404 "\n load (config_file)"
1405 "\nMedia Proprieties Syntax:"
1406 "\n input (input_name)"
1407 "\n output (output_name)"
1408 "\n option (option_name)[=value]"
1409 "\n enabled|disabled"
1410 "\n loop|unloop (broadcast only)"
1411 "\nSchedule Proprieties Syntax:"
1412 "\n enabled|disabled"
1413 "\n append (command_until_rest_of_the_line)"
1414 "\n date (year)/(month)/(day)-(hour):(minutes):(seconds)|now"
1415 "\n period (years_aka_12_months)/(months_aka_30_days)/(days)-(hours):(minutes):(seconds)"
1416 "\n repeat (number_of_repetitions)"
1417 "\nControl Commands Syntax:"
1418 "\n play\n pause\n stop\n seek (percentage)\n" );
1420 message = vlm_MessageNew( "help" , NULL );
1421 vlm_MessageAdd( message , vlm_MessageNew( "Help" , help ) );
1426 return vlm_MessageNew( "help" , NULL );
1429 /* file must end by '\0' */
1430 static int vlm_Load( vlm_t *vlm, char *file )
1434 while( *pf != '\0' )
1436 vlm_message_t *message = NULL;
1440 while( pf[i_temp] != '\n' && pf[i_temp] != '\0' && pf[i_temp] != '\r' )
1445 if( pf[i_temp] == '\r' || pf[i_temp] == '\n' )
1448 i_next = i_temp + 1;
1455 if( ExecuteCommand( vlm, pf, &message ) )
1467 static char *vlm_Save( vlm_t *vlm )
1474 for( i = 0; i < vlm->i_media; i++ )
1476 vlm_media_t *media = vlm->media[i];
1478 if( media->i_type == VOD_TYPE )
1480 i_length += strlen( "new vod " ) + strlen(media->psz_name);
1484 i_length += strlen( "new broadcast " ) + strlen(media->psz_name);
1487 if( media->b_enabled == VLC_TRUE )
1489 i_length += strlen( "enabled" );
1493 i_length += strlen( "disabled" );
1496 if( media->b_loop == VLC_TRUE )
1498 i_length += strlen( " loop\n" );
1502 i_length += strlen( "\n" );
1505 for( j = 0; j < media->i_input; j++ )
1507 i_length += strlen( "setup input \"\"\n" ) + strlen( media->psz_name ) + strlen( media->input[j] );
1510 if( media->psz_output != NULL )
1512 i_length += strlen(media->psz_name) + strlen(media->psz_output) + strlen( "setup output \n" );
1515 for( j=0 ; j < media->i_option ; j++ )
1517 i_length += strlen(media->psz_name) + strlen(media->option[j]) + strlen("setup option \n");
1521 for( i = 0; i < vlm->i_schedule; i++ )
1523 vlm_schedule_t *schedule = vlm->schedule[i];
1525 i_length += strlen( "new schedule " ) + strlen( schedule->psz_name );
1527 if( schedule->b_enabled == VLC_TRUE )
1529 i_length += strlen( "date //-:: enabled\n" ) + 14;
1533 i_length += strlen( "date //-:: disabled\n" ) + 14;
1537 if( schedule->i_period != 0 )
1539 i_length += strlen( "setup " ) + strlen( schedule->psz_name ) + strlen( "period //-::\n" ) + 14;
1542 if( schedule->i_repeat >= 0 )
1546 sprintf( buffer, "%d", schedule->i_repeat );
1547 i_length += strlen( "setup repeat \n" ) + strlen( schedule->psz_name ) + strlen( buffer );
1554 for( j = 0; j < schedule->i_command; j++ )
1556 i_length += strlen( "setup append \n" ) + strlen( schedule->psz_name ) + strlen( schedule->command[j] );
1561 /* Don't forget the '\0' */
1563 /* now we have the length of save */
1565 p = save = malloc( i_length );
1568 /* finally we can write in it */
1569 for( i = 0; i < vlm->i_media; i++ )
1571 vlm_media_t *media = vlm->media[i];
1573 if( media->i_type == VOD_TYPE )
1575 p += sprintf( p, "new %s vod ", media->psz_name);
1579 p += sprintf( p, "new %s broadcast ", media->psz_name);
1582 if( media->b_enabled == VLC_TRUE )
1584 p += sprintf( p, "enabled" );
1588 p += sprintf( p, "disabled" );
1591 if( media->b_loop == VLC_TRUE )
1593 p += sprintf( p, " loop\n" );
1597 p += sprintf( p, "\n" );
1600 for( j = 0; j < media->i_input; j++ )
1602 p += sprintf( p, "setup %s input \"%s\"\n", media->psz_name, media->input[j] );
1605 if( media->psz_output != NULL )
1607 p += sprintf( p, "setup %s output %s\n", media->psz_name, media->psz_output );
1610 for( j = 0; j < media->i_option; j++ )
1612 p += sprintf( p, "setup %s option %s\n", media->psz_name, media->option[j] );
1616 /* and now, the schedule scripts */
1618 for( i = 0; i < vlm->i_schedule; i++ )
1620 vlm_schedule_t *schedule = vlm->schedule[i];
1622 time_t i_time = (time_t) ( schedule->i_date / 1000000 );
1624 #ifdef HAVE_LOCALTIME_R
1625 localtime_r( &i_time, &date);
1627 struct tm *p_date = localtime( &i_time );
1631 p += sprintf( p, "new %s schedule ", schedule->psz_name);
1633 if( schedule->b_enabled == VLC_TRUE )
1635 p += sprintf( p, "date %d/%d/%d-%d:%d:%d enabled\n",
1636 date.tm_year + 1900, date.tm_mon + 1, date.tm_mday,
1637 date.tm_hour, date.tm_min, date.tm_sec );
1641 p += sprintf( p, "date %d/%d/%d-%d:%d:%d disabled\n",
1642 date.tm_year + 1900, date.tm_mon + 1, date.tm_mday,
1643 date.tm_hour, date.tm_min, date.tm_sec);
1647 if( schedule->i_period != 0 )
1649 p += sprintf( p, "setup %s ", schedule->psz_name );
1651 i_time = (time_t) ( schedule->i_period / 1000000 );
1653 date.tm_sec = (int)( i_time % 60 );
1654 i_time = i_time / 60;
1655 date.tm_min = (int)( i_time % 60 );
1656 i_time = i_time / 60;
1657 date.tm_hour = (int)( i_time % 24 );
1658 i_time = i_time / 24;
1659 date.tm_mday = (int)( i_time % 30 );
1660 i_time = i_time / 30;
1661 /* okay, okay, months are not always 30 days long */
1662 date.tm_mon = (int)( i_time % 12 );
1663 i_time = i_time / 12;
1664 date.tm_year = (int)i_time;
1666 p += sprintf( p, "period %d/%d/%d-%d:%d:%d\n", date.tm_year ,
1674 if( schedule->i_repeat >= 0 )
1676 p += sprintf( p, "setup %s repeat %d\n", schedule->psz_name, schedule->i_repeat );
1680 p += sprintf( p, "\n" );
1683 for( j = 0; j < schedule->i_command; j++ )
1685 p += sprintf( p, "setup %s append %s\n", schedule->psz_name, schedule->command[j] );
1693 /*****************************************************************************
1695 *****************************************************************************/
1696 vlm_t *__vlm_New ( vlc_object_t *p_object )
1698 vlm_t *vlm = vlc_object_create( p_object , sizeof( vlm_t ) );
1700 vlc_mutex_init( p_object->p_vlc, &vlm->lock );
1703 vlm->i_schedule = 0;
1704 vlm->schedule = NULL;
1706 if( vlc_thread_create( vlm, "vlm thread",
1707 Manage, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
1710 vlc_mutex_destroy( &vlm->lock );
1711 vlc_object_destroy( vlm );
1717 /*****************************************************************************
1719 *****************************************************************************/
1720 void vlm_Delete( vlm_t *vlm )
1724 vlm->b_die = VLC_TRUE;
1725 vlc_thread_join( vlm );
1727 vlc_mutex_destroy( &vlm->lock );
1729 for( i = 0; i < vlm->i_media; i++ )
1731 vlm_media_t *media = vlm->media[i];
1733 vlm_MediaDelete( vlm, media, NULL );
1736 if( vlm->media ) free( vlm->media );
1738 for( i = 0; i < vlm->i_schedule; i++ )
1740 vlm_ScheduleDelete( vlm, vlm->schedule[i], NULL );
1743 if( vlm->schedule ) free( vlm->schedule );
1745 vlc_object_destroy( vlm );
1748 static vlm_schedule_t *vlm_ScheduleNew( vlm_t *vlm , char *psz_name )
1750 vlm_schedule_t *sched= malloc( sizeof( vlm_schedule_t ));
1752 sched->psz_name = strdup( psz_name );
1753 sched->b_enabled = VLC_FALSE;
1754 sched->i_command = 0;
1755 sched->command = NULL;
1757 sched->i_period = 0;
1758 sched->i_repeat = 0;
1760 TAB_APPEND( vlm->i_schedule , vlm->schedule , sched );
1765 /* for now, simple delete. After, del with options (last arg) */
1766 static int vlm_ScheduleDelete( vlm_t *vlm, vlm_schedule_t *sched, char *psz_name )
1775 TAB_REMOVE( vlm->i_schedule, vlm->schedule , sched );
1777 if( vlm->i_schedule == 0 && vlm->schedule ) free( vlm->schedule );
1779 free( sched->psz_name );
1781 for( i = 0; i < sched->i_command; i++ )
1783 free( sched->command[i] );
1791 static vlm_schedule_t *vlm_ScheduleSearch( vlm_t *vlm, char *psz_name )
1795 for( i = 0; i < vlm->i_schedule; i++ )
1797 if( strcmp( psz_name, vlm->schedule[i]->psz_name ) == 0 )
1799 return vlm->schedule[i];
1806 /* Ok, setup schedule command will be able to support only one (argument value) at a time */
1807 static int vlm_ScheduleSetup( vlm_schedule_t *schedule, char *psz_cmd, char *psz_value )
1809 if( strcmp( psz_cmd, "enabled" ) == 0 )
1811 schedule->b_enabled = VLC_TRUE;
1813 else if( strcmp( psz_cmd, "disabled" ) == 0 )
1815 schedule->b_enabled = VLC_FALSE;
1817 else if( strcmp( psz_cmd, "date" ) == 0 )
1823 time.tm_sec = 0; /* seconds */
1824 time.tm_min = 0; /* minutes */
1825 time.tm_hour = 0; /* hours */
1826 time.tm_mday = 0; /* day of the month */
1827 time.tm_mon = 0; /* month */
1828 time.tm_year = 0; /* year */
1829 time.tm_wday = 0; /* day of the week */
1830 time.tm_yday = 0; /* day in the year */
1831 time.tm_isdst = 0; /* daylight saving time */
1833 /* date should be year/month/day-hour:minutes:seconds */
1834 p = strchr( psz_value , '-' );
1836 if( strcmp( psz_value, "now" ) == 0 )
1838 schedule->i_date = 0;
1840 else if( p == NULL && sscanf( psz_value, "%d:%d:%d" , &time.tm_hour, &time.tm_min, &time.tm_sec ) != 3 ) /* it must be a hour:minutes:seconds */
1848 switch( sscanf( p + 1, "%d:%d:%d" , &i, &j, &k ) )
1868 switch( sscanf( psz_value, "%d/%d/%d" , &i, &j, &k ) )
1874 time.tm_mon = i - 1;
1878 time.tm_year = i - 1900;
1879 time.tm_mon = j - 1;
1886 date = mktime( &time );
1887 schedule->i_date = ((mtime_t) date) * 1000000;
1890 else if( strcmp( psz_cmd, "period" ) == 0 )
1896 /* First, if date or period are modified, repeat should be equal to -1 */
1897 schedule->i_repeat = -1;
1899 time.tm_sec = 0; /* seconds */
1900 time.tm_min = 0; /* minutes */
1901 time.tm_hour = 0; /* hours */
1902 time.tm_mday = 0; /* day of the month */
1903 time.tm_mon = 0; /* month */
1904 time.tm_year = 0; /* year */
1905 time.tm_wday = 0; /* day of the week */
1906 time.tm_yday = 0; /* day in the year */
1907 time.tm_isdst = 0; /* daylight saving time */
1909 /* date should be year/month/day-hour:minutes:seconds */
1910 p = strchr( psz_value , '-' );
1912 if( p == NULL && sscanf( psz_value, "%d:%d:%d" , &time.tm_hour, &time.tm_min, &time.tm_sec ) != 3 ) /* it must be a hour:minutes:seconds */
1920 switch( sscanf( p + 1, "%d:%d:%d" , &i, &j, &k ) )
1940 switch( sscanf( psz_value, "%d/%d/%d" , &i, &j, &k ) )
1959 /* ok, that's stupid... who is going to schedule streams every 42 years ? */
1960 date = (((( time.tm_year * 12 + time.tm_mon ) * 30 + time.tm_mday ) * 24 + time.tm_hour ) * 60 + time.tm_min ) * 60 + time.tm_sec ;
1961 schedule->i_period = ((mtime_t) date) * 1000000;
1963 else if( strcmp( psz_cmd, "repeat" ) == 0 )
1967 if( sscanf( psz_value, "%d" , &i ) == 1 )
1969 schedule->i_repeat = i;
1976 else if( strcmp( psz_cmd, "append" ) == 0 )
1978 char *command = strdup( psz_value );
1980 TAB_APPEND( schedule->i_command, schedule->command, command );
1989 /*****************************************************************************
1991 *****************************************************************************/
1992 static int Manage( vlc_object_t* p_object )
1994 vlm_t *vlm = (vlm_t*)p_object;
1996 mtime_t i_lastcheck;
1999 i_lastcheck = mdate();
2003 while( !vlm->b_die )
2005 vlc_mutex_lock( &vlm->lock );
2007 /* destroy the inputs that wants to die, and launch the next input */
2008 for( i = 0; i < vlm->i_media; i++ )
2010 vlm_media_t *media = vlm->media[i];
2012 if( media->p_input != NULL && ( media->p_input->b_eof || media->p_input->b_error ) )
2014 input_StopThread( media->p_input );
2016 input_DestroyThread( media->p_input );
2017 vlc_object_detach( media->p_input );
2018 vlc_object_destroy( media->p_input );
2019 media->p_input = NULL;
2022 if( media->i_index == media->i_input && media->b_loop == VLC_TRUE )
2027 if( media->i_index < media->i_input )
2031 sprintf( buffer, "%d", media->i_index );
2032 vlm_MediaControl( vlm, media, "play", buffer );
2040 for( i = 0; i < vlm->i_schedule; i++ )
2042 mtime_t i_real_date = vlm->schedule[i]->i_date;
2044 if( vlm->schedule[i]->i_date == 0 ) // now !
2046 vlm->schedule[i]->i_date = (i_time / 1000000) * 1000000 ;
2047 i_real_date = i_time;
2049 else if( vlm->schedule[i]->i_period != 0 )
2052 while( vlm->schedule[i]->i_date + j * vlm->schedule[i]->i_period <= i_lastcheck &&
2053 ( vlm->schedule[i]->i_repeat > j || vlm->schedule[i]->i_repeat == -1 ) )
2058 i_real_date = vlm->schedule[i]->i_date + j * vlm->schedule[i]->i_period;
2061 if( vlm->schedule[i]->b_enabled == VLC_TRUE )
2063 if( i_real_date <= i_time && i_real_date > i_lastcheck )
2065 for( j = 0 ; j < vlm->schedule[i]->i_command ; j++ )
2067 vlm_message_t *message = NULL;
2069 ExecuteCommand( vlm, vlm->schedule[i]->command[j] , &message );
2071 /* for now, drop the message */
2078 i_lastcheck = i_time;
2080 vlc_mutex_unlock( &vlm->lock );
2089 void vlm_MessageDelete( vlm_message_t* message )
2093 if( message->psz_name ) free( message->psz_name );
2094 if( message->psz_value ) free( message->psz_value );
2096 for( i = 0; i < message->i_child; i++)
2098 vlm_MessageDelete( message->child[i] );
2104 static vlm_message_t* vlm_MessageNew( char *psz_name , char *psz_value )
2106 vlm_message_t *message = malloc( sizeof(vlm_message_t) );
2110 message->psz_name = strdup( psz_name );
2119 message->psz_value = strdup( psz_value );
2123 message->psz_value = NULL;
2126 message->i_child = 0;
2127 message->child = NULL;
2133 static vlm_message_t* vlm_MessageAdd( vlm_message_t* message , vlm_message_t* child )
2135 if( message == NULL ) return NULL;
2139 TAB_APPEND( message->i_child , message->child , child );