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() */
32 #include <vlc/input.h>
35 # include <time.h> /* ctime() */
40 /*****************************************************************************
42 *****************************************************************************/
43 static char *vlm_Save( vlm_t * );
44 static int vlm_Load( vlm_t *, char *);
45 static vlm_message_t *vlm_Show( vlm_t *, vlm_media_t *, vlm_schedule_t *, char * );
46 static vlm_message_t *vlm_Help( vlm_t *, char * );
48 static vlm_media_t *vlm_MediaNew ( vlm_t *, char *, int );
49 static int vlm_MediaDelete ( vlm_t *, vlm_media_t *, char * );
50 static vlm_media_t *vlm_MediaSearch ( vlm_t *, char * );
51 static int vlm_MediaSetup ( vlm_media_t *, char *, char * );
52 static int vlm_MediaControl( vlm_t *, vlm_media_t *, char *, 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 *);
63 static int ExecuteCommand( vlm_t *, char * , vlm_message_t **);
65 static int Manage( vlc_object_t* );
67 /*****************************************************************************
69 *****************************************************************************/
70 vlm_t *__vlm_New ( vlc_object_t *p_this )
75 /* to be sure to avoid multiple creation */
76 var_Create( p_this->p_libvlc, "vlm_mutex", VLC_VAR_MUTEX );
77 var_Get( p_this->p_libvlc, "vlm_mutex", &lockval );
78 vlc_mutex_lock( lockval.p_address );
80 if( !(vlm = vlc_object_find( p_this, VLC_OBJECT_VLM, FIND_ANYWHERE )) )
82 msg_Info( p_this, "creating vlm" );
83 if( ( vlm = vlc_object_create( p_this, VLC_OBJECT_VLM ) ) == NULL )
85 vlc_mutex_unlock( lockval.p_address );
89 vlc_mutex_init( p_this->p_vlc, &vlm->lock );
95 vlc_object_yield( vlm );
96 vlc_object_attach( vlm, p_this->p_vlc );
98 vlc_mutex_unlock( lockval.p_address );
101 if( vlc_thread_create( vlm, "vlm thread",
102 Manage, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
104 vlc_mutex_destroy( &vlm->lock );
105 vlc_object_destroy( vlm );
111 /*****************************************************************************
113 *****************************************************************************/
114 void vlm_Delete( vlm_t *vlm )
119 var_Get( vlm->p_libvlc, "vlm_mutex", &lockval );
120 vlc_mutex_lock( lockval.p_address );
122 vlc_object_release( vlm );
124 if( vlm->i_refcount > 0 )
126 vlc_mutex_unlock( lockval.p_address );
130 vlm->b_die = VLC_TRUE;
131 vlc_thread_join( vlm );
133 vlc_mutex_destroy( &vlm->lock );
135 for( i = 0; i < vlm->i_media; i++ )
137 vlm_media_t *media = vlm->media[i];
139 vlm_MediaDelete( vlm, media, NULL );
142 if( vlm->media ) free( vlm->media );
144 for( i = 0; i < vlm->i_schedule; i++ )
146 vlm_ScheduleDelete( vlm, vlm->schedule[i], NULL );
149 if( vlm->schedule ) free( vlm->schedule );
151 vlc_object_detach( vlm );
152 vlc_object_destroy( vlm );
153 vlc_mutex_unlock( lockval.p_address );
156 /*****************************************************************************
157 * vlm_ExecuteCommand:
158 *****************************************************************************/
159 int vlm_ExecuteCommand( vlm_t *vlm, char *command, vlm_message_t **message)
163 vlc_mutex_lock( &vlm->lock );
164 result = ExecuteCommand( vlm, command, message );
165 vlc_mutex_unlock( &vlm->lock );
170 /*****************************************************************************
172 *****************************************************************************/
174 static char *FindEndCommand( char *psz )
184 while( ( *s_sent != '\"' ) && ( *s_sent != '\0' ) )
186 if( *s_sent == '\'' )
188 s_sent = FindEndCommand( s_sent );
201 if( *s_sent == '\"' )
206 else /* *s_sent == '\0' , which means the number of " is incorrect */
216 while( ( *s_sent != '\'' ) && ( *s_sent != '\0' ) )
218 if( *s_sent == '\"' )
220 s_sent = FindEndCommand( s_sent );
233 if( *s_sent == '\'' )
238 else /* *s_sent == '\0' , which means the number of ' is incorrect */
244 default: /* now we can look for spaces */
246 while( ( *s_sent != ' ' ) && ( *s_sent != '\0' ) )
248 if( ( *s_sent == '\'' ) || ( *s_sent == '\"' ) )
250 s_sent = FindEndCommand( s_sent );
262 static char *FindEndCommand( char *psz )
267 *psz != ' ' && *psz != '\t' &&
268 *psz != '\n' && *psz != '\r' )
270 if( *psz == '\'' || *psz == '"' )
274 while( *psz && *psz != d && *psz != *psz != '\n' && *psz != '\r' )
276 if( ( d == '\'' && *psz == '"' ) ||
277 ( d == '"' && *psz == '\'' ) )
279 psz = FindEndCommand( psz );
293 /* Execute a command which ends by '\0' (string) */
294 static int ExecuteCommand( vlm_t *vlm, char *command , vlm_message_t **p_message)
298 char **p_command = NULL;
301 vlm_message_t * message = NULL;
303 /* First, parse the line and cut it */
304 while( *cmd != '\0' )
316 p_temp = FindEndCommand( cmd );
324 i_temp = p_temp - cmd;
326 p_command = realloc( p_command , (i_command + 1) * sizeof( char* ) );
327 p_command[ i_command ] = malloc( (i_temp + 1) * sizeof( char ) ); // don't forget the '\0'
328 strncpy( p_command[ i_command ] , cmd , i_temp );
329 (p_command[ i_command ])[ i_temp ] = '\0';
336 /* And then Interpret it */
340 message = vlm_MessageNew( "" , NULL );
345 if( strcmp(p_command[0] , "segfault") == 0 )
347 /* the only command we really need */
350 else if( strcmp(p_command[0] , "new") == 0 )
356 vlm_schedule_t *schedule;
358 if( strcmp(p_command[2] , "schedule") == 0 )
360 /* new vlm_schedule */
361 if( vlm_ScheduleSearch( vlm , p_command[1] ) != NULL || strcmp(p_command[1] , "schedule") == 0 )
363 char *error_message = malloc( strlen(p_command[1]) + strlen(" is already used") + 1 );
364 sprintf( error_message, "%s is already used" , p_command[1] );
365 message = vlm_MessageNew( "new" , error_message );
366 free( error_message );
371 schedule = vlm_ScheduleNew( vlm , p_command[1] );
374 if( i_command > 3 ) // hey, there are properties
376 for( i = 3 ; i < i_command ; i++ )
378 if( strcmp( p_command[i] , "enabled" ) == 0 || strcmp( p_command[i] , "disabled" ) == 0 )
380 vlm_ScheduleSetup( schedule, p_command[i], NULL );
382 /* Beware: evrything behind append is considered as command line */
383 else if( strcmp( p_command[i] , "append" ) == 0 )
390 for( j = (i + 1); j < i_command; j++ )
392 p_command[i] = realloc( p_command[i], strlen(p_command[i]) + strlen(p_command[j]) + 1 + 1);
393 strcat( p_command[i], " " );
394 strcat( p_command[i], p_command[j] );
397 vlm_ScheduleSetup( schedule, p_command[i - 1], p_command[i] );
403 if( (i+1) < i_command )
405 vlm_ScheduleSetup( schedule, p_command[i], p_command[i+1] );
410 vlm_ScheduleDelete( vlm, schedule, NULL );
411 message = vlm_MessageNew( p_command[i], "Wrong properties syntax" );
418 message = vlm_MessageNew( "new" , NULL );
423 message = vlm_MessageNew( "new" , NULL );
428 if( strcmp(p_command[2] , "vod") == 0 )
432 else if( strcmp(p_command[2] , "broadcast") == 0 )
434 i_type = BROADCAST_TYPE;
438 char *error_message = malloc( strlen(p_command[1]) + strlen(": Choose between vod or broadcast") + 1 );
439 sprintf( error_message, "%s: Choose between vod or broadcast" , p_command[1] );
440 message = vlm_MessageNew( "new" , error_message );
441 free( error_message );
447 if( vlm_MediaSearch( vlm , p_command[1] ) != NULL || strcmp(p_command[1] , "media") == 0 )
449 char *error_message = malloc( strlen(p_command[1]) + strlen(" is already used") + 1 );
450 sprintf( error_message, "%s is already used" , p_command[1] );
451 message = vlm_MessageNew( "new" , error_message );
452 free( error_message );
457 media = vlm_MediaNew( vlm , p_command[1] , i_type );
459 if( i_command > 3 ) // hey, there are properties
461 for( i = 3 ; i < i_command ; i++ )
463 if( strcmp( p_command[i] , "enabled" ) == 0 || strcmp( p_command[i] , "disabled" ) == 0 )
465 vlm_MediaSetup( media, p_command[i], NULL );
469 if( (i+1) < i_command )
471 vlm_MediaSetup( media, p_command[i], p_command[i+1] );
476 vlm_MediaDelete( vlm, media, NULL );
477 message = vlm_MessageNew( p_command[i] , "Wrong properties syntax" );
484 message = vlm_MessageNew( "new" , NULL );
489 message = vlm_MessageNew( "new" , NULL );
495 message = vlm_MessageNew( "new" , "Wrong command syntax" );
500 else if( strcmp(p_command[0] , "del") == 0 )
505 vlm_schedule_t *schedule;
507 media = vlm_MediaSearch( vlm , p_command[1] );
508 schedule = vlm_ScheduleSearch( vlm , p_command[1] );
510 if( schedule != NULL )
512 vlm_ScheduleDelete( vlm, schedule, NULL );
513 message = vlm_MessageNew( "del" , NULL );
517 else if( media != NULL )
519 vlm_MediaDelete( vlm, media, NULL );
520 message = vlm_MessageNew( "del" , NULL );
524 else if( strcmp(p_command[1] , "media") == 0 )
526 for( i = 0; i < vlm->i_media; i++ )
528 vlm_MediaDelete( vlm, vlm->media[i], NULL );
530 message = vlm_MessageNew( "del", NULL );
533 else if( strcmp(p_command[1] , "schedule") == 0 )
535 for( i = 0; i < vlm->i_schedule; i++ )
537 vlm_ScheduleDelete( vlm, vlm->schedule[i], NULL );
539 message = vlm_MessageNew( "del", NULL );
542 else if( strcmp(p_command[1] , "all") == 0 )
544 for( i = 0; i < vlm->i_media; i++ )
546 vlm_MediaDelete( vlm, vlm->media[i], NULL );
549 for( i = 0; i < vlm->i_schedule; i++ )
551 vlm_ScheduleDelete( vlm, vlm->schedule[i], NULL );
554 message = vlm_MessageNew( "del", NULL );
559 char *error_message = malloc( strlen(p_command[1]) + strlen(": media unknown") + 1 );
560 sprintf( error_message, "%s: media unknown" , p_command[1] );
561 message = vlm_MessageNew( "del" , error_message );
562 free( error_message );
569 message = vlm_MessageNew( "setup" , "Wrong command syntax" );
574 else if( strcmp(p_command[0] , "show") == 0 )
578 message = vlm_Show( vlm, NULL , NULL, NULL );
582 else if( i_command == 2 )
585 vlm_schedule_t *schedule;
587 media = vlm_MediaSearch( vlm , p_command[1] );
588 schedule = vlm_ScheduleSearch( vlm , p_command[1] );
590 if( schedule != NULL )
592 message = vlm_Show( vlm, NULL, schedule, NULL );
594 else if( media != NULL )
596 message = vlm_Show( vlm, media, NULL, NULL );
600 message = vlm_Show( vlm, NULL, NULL, p_command[1] );
608 message = vlm_MessageNew( "show" , "Wrong command syntax" );
613 else if( strcmp(p_command[0] , "help") == 0 )
617 message = vlm_Help( vlm, NULL );
623 message = vlm_MessageNew( "help" , "Wrong command syntax" );
628 else if( strcmp(p_command[0] , "setup") == 0 )
633 vlm_schedule_t *schedule;
635 media = vlm_MediaSearch( vlm , p_command[1] );
636 schedule = vlm_ScheduleSearch( vlm , p_command[1] );
638 if( schedule != NULL )
640 for( i = 2 ; i < i_command ; i++ )
642 if( strcmp( p_command[i] , "enabled" ) == 0 || strcmp( p_command[i] , "disabled" ) == 0 )
644 vlm_ScheduleSetup( schedule, p_command[i], NULL );
646 /* Beware: evrything behind append is considered as command line */
647 else if( strcmp( p_command[i] , "append" ) == 0 )
654 for( j = (i + 1); j < i_command; j++ )
656 p_command[i] = realloc( p_command[i], strlen(p_command[i]) + strlen(p_command[j]) + 1 + 1);
657 strcat( p_command[i], " " );
658 strcat( p_command[i], p_command[j] );
661 vlm_ScheduleSetup( schedule, p_command[i - 1], p_command[i] );
667 if( (i+1) < i_command )
669 vlm_ScheduleSetup( schedule, p_command[i], p_command[i+1] );
674 vlm_ScheduleDelete( vlm, schedule, NULL );
675 message = vlm_MessageNew( "setup" , "Wrong properties syntax" );
682 message = vlm_MessageNew( "setup" , NULL );
686 else if( media != NULL )
688 for( i = 2 ; i < i_command ; i++ )
690 if( strcmp( p_command[i] , "enabled" ) == 0 || strcmp( p_command[i] , "disabled" ) == 0 )
691 { /* only one argument */
692 vlm_MediaSetup( media, p_command[i], NULL );
694 else if( strcmp( p_command[i] , "loop" ) == 0 || strcmp( p_command[i] , "unloop" ) == 0 )
696 if( media->i_type != BROADCAST_TYPE )
698 message = vlm_MessageNew( "setup" , "lool only available for broadcast" );
704 vlm_MediaSetup( media, p_command[i], NULL );
709 if( (i+1) < i_command )
711 vlm_MediaSetup( media, p_command[i], p_command[i+1] );
716 vlm_MediaDelete( vlm, media, NULL );
717 message = vlm_MessageNew( "setup" , "Wrong properties syntax" );
724 message = vlm_MessageNew( "setup" , NULL );
730 char *error_message = malloc( strlen(p_command[1]) + strlen(" unknown") + 1 );
731 sprintf( error_message, "%s unknown" , p_command[1] );
732 message = vlm_MessageNew( "setup" , error_message );
733 free( error_message );
741 message = vlm_MessageNew( "setup" , "Wrong command syntax" );
746 else if( strcmp(p_command[0] , "control") == 0 )
753 media = vlm_MediaSearch( vlm , p_command[1] );
757 char *error_message = malloc( strlen(p_command[1]) + strlen(": media unknown") + 1 );
758 sprintf( error_message, "%s: media unknown" , p_command[1] );
759 message = vlm_MessageNew( "control" , error_message );
760 free( error_message );
770 psz_args = p_command[3];
778 vlm_MediaControl( vlm, media, p_command[2], psz_args );
779 message = vlm_MessageNew( "control" , NULL );
786 message = vlm_MessageNew( "control" , "Wrong command syntax" );
791 else if( strcmp(p_command[0] , "save") == 0 )
798 file = fopen( p_command[1], "w" );
802 message = vlm_MessageNew( "save" , "Unable to save file" );
810 save = vlm_Save( vlm );
812 fwrite( save, strlen( save ) , 1 , file );
815 message = vlm_MessageNew( "save" , NULL );
822 message = vlm_MessageNew( "save" , "Wrong command" );
827 else if( strcmp(p_command[0] , "load") == 0 )
834 file = fopen( p_command[1], "r" );
838 message = vlm_MessageNew( "load" , "Unable to load file" );
847 if( fseek( file, 0, SEEK_END) == 0 )
849 size = ftell( file );
850 fseek( file, 0, SEEK_SET);
851 buffer = malloc( size + 1 );
852 fread( buffer, 1, size, file);
853 buffer[ size ] = '\0';
854 if( vlm_Load( vlm, buffer ) )
857 message = vlm_MessageNew( "load" , "error while loading file" );
865 message = vlm_MessageNew( "load" , "read file error" );
870 message = vlm_MessageNew( "load" , NULL );
877 message = vlm_MessageNew( "load" , "Wrong command" );
884 message = vlm_MessageNew( p_command[0] , "Unknown comand" );
891 for( i = 0 ; i < i_command ; i++ )
893 free( p_command[i] );
896 *p_message = message;
902 static vlm_media_t *vlm_MediaSearch( vlm_t *vlm, char *psz_name )
906 for( i = 0; i < vlm->i_media; i++ )
908 if( strcmp( psz_name, vlm->media[i]->psz_name ) == 0 )
910 return vlm->media[i];
918 static vlm_media_t *vlm_MediaNew( vlm_t *vlm , char *psz_name, int i_type )
920 vlm_media_t *media= malloc( sizeof( vlm_media_t ));
922 media->psz_name = strdup( psz_name );
923 media->b_enabled = VLC_FALSE;
924 media->b_loop = VLC_FALSE;
928 media->psz_output = NULL;
930 media->option = NULL;
931 media->i_type = i_type;
932 media->p_input = NULL;
934 media->item.psz_uri = strdup( psz_name );
935 media->item.psz_name = NULL;
936 media->item.i_duration = -1;
937 media->item.ppsz_options = NULL;
938 media->item.i_options = 0;
939 media->item.i_categories = 0;
940 media->item.pp_categories = NULL;
941 vlc_mutex_init( vlm, &media->item.lock );
943 TAB_APPEND( vlm->i_media, vlm->media, media );
949 /* for now, simple delete. After, del with options (last arg) */
950 static int vlm_MediaDelete( vlm_t *vlm, vlm_media_t *media, char *psz_name )
961 input_StopThread( media->p_input );
963 input_DestroyThread( media->p_input );
964 vlc_object_detach( media->p_input );
965 vlc_object_destroy( media->p_input );
968 TAB_REMOVE( vlm->i_media, vlm->media , media );
970 if( vlm->i_media == 0 && vlm->media ) free( vlm->media );
972 free( media->psz_name );
974 for( i = 0; i < media->i_input; i++ )
976 free( media->input[i] );
978 if( media->input ) free( media->input );
980 if( media->psz_output ) free( media->psz_output );
982 for( i = 0; i < media->i_option; i++ )
984 free( media->option[i] );
986 if(media->option) free( media->option );
988 if( media->item.psz_uri ) free( media->item.psz_uri );
989 if( media->item.psz_name ) free( media->item.psz_name );
990 vlc_mutex_destroy( &media->item.lock );
991 for( i = 0; i < media->item.i_options; i++ )
993 free( media->item.ppsz_options[i] );
995 if( media->item.ppsz_options ) free( media->item.ppsz_options );
996 /* FIXME: free the info categories. */
1004 static int vlm_MediaSetup( vlm_media_t *media, char *psz_cmd, char *psz_value )
1006 if( strcmp( psz_cmd, "loop" ) == 0 )
1008 media->b_loop = VLC_TRUE;
1010 else if( strcmp( psz_cmd, "unloop" ) == 0 )
1012 media->b_loop = VLC_FALSE;
1014 else if( strcmp( psz_cmd, "enabled" ) == 0 )
1016 media->b_enabled = VLC_TRUE;
1018 else if( strcmp( psz_cmd, "disabled" ) == 0 )
1020 media->b_enabled = VLC_FALSE;
1022 else if( strcmp( psz_cmd, "input" ) == 0 )
1026 if( psz_value != NULL && strlen(psz_value) > 1 && ( psz_value[0] == '\'' || psz_value[0] == '\"' )
1027 && ( psz_value[ strlen(psz_value) - 1 ] == '\'' || psz_value[ strlen(psz_value) - 1 ] == '\"' ) )
1029 input = malloc( strlen(psz_value) - 1 );
1031 memcpy( input , psz_value + 1 , strlen(psz_value) - 2 );
1032 input[ strlen(psz_value) - 2 ] = '\0';
1036 input = strdup( psz_value );
1039 TAB_APPEND( media->i_input, media->input, input );
1041 else if( strcmp( psz_cmd, "output" ) == 0 )
1043 if( media->psz_output != NULL )
1045 free( media->psz_output );
1047 media->psz_output = strdup( psz_value );
1049 else if( strcmp( psz_cmd, "option" ) == 0 )
1052 option = strdup( psz_value );
1054 TAB_APPEND( media->i_option, media->option, option );
1063 static int vlm_MediaControl( vlm_t *vlm, vlm_media_t *media, char *psz_name,
1066 if( strcmp( psz_name, "play" ) == 0 )
1070 if( media->b_enabled == VLC_TRUE && media->i_input > 0 )
1072 if( psz_args != NULL && sscanf( psz_args, "%d", &i ) == 1 &&
1073 i < media->i_input )
1082 if( media->item.psz_uri )
1084 free( media->item.psz_uri );
1085 media->item.psz_uri =NULL;
1087 media->item.psz_uri = strdup( media->input[media->i_index] );
1089 /* FIXME!!! we need an input_item_t per input spawned */
1090 //input_ItemNew( &media->item );
1091 if( media->psz_output != NULL )
1093 media->item.ppsz_options = malloc( sizeof( char* ) );
1094 media->item.ppsz_options[0] =
1095 malloc( strlen(media->psz_output) + sizeof("sout=") );
1096 sprintf( media->item.ppsz_options[0], "sout=%s",
1097 media->psz_output );
1098 media->item.i_options = 1;
1102 media->item.ppsz_options = NULL;
1103 media->item.i_options = 0;
1106 for( i = 0; i < media->i_option; i++ )
1108 media->item.i_options++;
1109 media->item.ppsz_options =
1110 realloc( media->item.ppsz_options,
1111 media->item.i_options * sizeof( char* ) );
1112 media->item.ppsz_options[ media->item.i_options - 1 ] =
1113 strdup( media->option[i] );
1116 media->p_input = input_CreateThread( vlm, &media->item );
1125 else if( strcmp( psz_name, "seek" ) == 0 )
1130 if( psz_args && sscanf( psz_args, "%f", &f_percentage ) == 1 )
1132 val.f_float = f_percentage / 100.0 ;
1133 var_Set( media->p_input, "position", val );
1137 else if( strcmp( psz_name, "stop" ) == 0 )
1139 /* FIXME!!! we need an input_item_t per input spawned */
1140 if( media->p_input )
1142 input_StopThread( media->p_input );
1143 input_DestroyThread( media->p_input );
1144 vlc_object_detach( media->p_input );
1145 vlc_object_destroy( media->p_input );
1146 media->p_input = NULL;
1148 //input_ItemDelete( &media->item );
1153 else if( strcmp( psz_name, "pause" ) == 0 )
1159 if( media->p_input != NULL )
1161 var_Get( media->p_input, "state", &val );
1164 if( val.i_int == PAUSE_S )
1166 if( media->p_input )
1168 val.i_int = PLAYING_S;
1169 var_Set( media->p_input, "state", val );
1174 if( media->p_input )
1176 val.i_int = PAUSE_S;
1177 var_Set( media->p_input, "state", val );
1186 static vlm_message_t *vlm_Show( vlm_t *vlm, vlm_media_t *media, vlm_schedule_t *schedule, char *psz_filter )
1192 vlm_message_t *message;
1193 vlm_message_t *message_media;
1194 vlm_message_t *message_child;
1196 message = vlm_MessageNew( "show" , NULL );
1197 message_media = vlm_MessageAdd( message , vlm_MessageNew( media->psz_name , NULL ) );
1199 if( media->i_type == VOD_TYPE )
1201 vlm_MessageAdd( message_media , vlm_MessageNew( "type" , "vod" ) );
1205 vlm_MessageAdd( message_media , vlm_MessageNew( "type" , "broadcast" ) );
1208 vlm_MessageAdd( message_media , vlm_MessageNew( "enabled" , media->b_enabled ? "yes" : "no" ) );
1210 vlm_MessageAdd( message_media, vlm_MessageNew( "loop" , media->b_loop ? "yes" : "no" ) );
1212 message_child = vlm_MessageAdd( message_media , vlm_MessageNew( "inputs" , NULL ) );
1214 for( i=0 ; i < (media->i_input) ; i++ )
1216 vlm_MessageAdd( message_child , vlm_MessageNew( media->input[i] , NULL ) );
1219 vlm_MessageAdd( message_media , vlm_MessageNew( "output" , media->psz_output ? media->psz_output : "" ) );
1221 message_child = vlm_MessageAdd( message_media , vlm_MessageNew( "options" , NULL ) );
1223 for( i=0 ; i < (media->i_option) ; i++ )
1225 vlm_MessageAdd( message_child , vlm_MessageNew( media->option[i] , NULL ) );
1228 if( media->p_input != NULL )
1232 var_Get( media->p_input, "state", &val );
1234 if( val.i_int == PLAYING_S )
1236 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "playing" ) );
1238 else if( val.i_int == PAUSE_S )
1240 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "paused" ) );
1244 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "stop" ) );
1249 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "stop" ) );
1255 else if( schedule != NULL )
1258 vlm_message_t *message;
1259 vlm_message_t *message_schedule;
1260 vlm_message_t *message_child;
1263 message = vlm_MessageNew( "show" , NULL );
1264 message_schedule = vlm_MessageAdd( message , vlm_MessageNew( schedule->psz_name , NULL ) );
1266 vlm_MessageAdd( message_schedule , vlm_MessageNew( "type" , "schedule" ) );
1268 if( schedule->b_enabled == VLC_TRUE )
1270 vlm_MessageAdd( message_schedule , vlm_MessageNew( "enabled" , "yes" ) );
1274 vlm_MessageAdd( message_schedule , vlm_MessageNew( "enabled" , "no" ) );
1277 if( schedule->i_date != 0 )
1280 time_t i_time = (time_t) ( schedule->i_date / 1000000 );
1281 char *psz_date = malloc( strlen( "//-::" ) + 14 );
1283 #ifdef HAVE_LOCALTIME_R
1284 localtime_r( &i_time, &date);
1286 struct tm *p_date = localtime( &i_time );
1290 sprintf( psz_date, "%d/%d/%d-%d:%d:%d",
1291 date.tm_year + 1900, date.tm_mon + 1, date.tm_mday,
1292 date.tm_hour, date.tm_min, date.tm_sec );
1295 time_t i_time = schedule->i_date / (int64_t)1000000;
1299 ctime_r( &i_time, psz_date );
1301 char *psz_date = ctime( &i_time );
1304 vlm_MessageAdd( message_schedule , vlm_MessageNew( "date" , psz_date ) );
1309 vlm_MessageAdd( message_schedule , vlm_MessageNew( "date" , "now" ) );
1312 if( schedule->i_period != 0 )
1314 time_t i_time = (time_t) ( schedule->i_period / 1000000 );
1317 date.tm_sec = (int)( i_time % 60 );
1318 i_time = i_time / 60;
1319 date.tm_min = (int)( i_time % 60 );
1320 i_time = i_time / 60;
1321 date.tm_hour = (int)( i_time % 24 );
1322 i_time = i_time / 24;
1323 date.tm_mday = (int)( i_time % 30 );
1324 i_time = i_time / 30;
1325 /* okay, okay, months are not always 30 days long */
1326 date.tm_mon = (int)( i_time % 12 );
1327 i_time = i_time / 12;
1328 date.tm_year = (int)i_time;
1330 sprintf( buffer, "%d/%d/%d-%d:%d:%d", date.tm_year, date.tm_mon,
1331 date.tm_mday, date.tm_hour, date.tm_min, date.tm_sec);
1333 vlm_MessageAdd( message_schedule , vlm_MessageNew( "period" , buffer ) );
1337 vlm_MessageAdd( message_schedule , vlm_MessageNew( "period" , "0" ) );
1340 sprintf( buffer, "%d" , schedule->i_repeat );
1341 vlm_MessageAdd( message_schedule , vlm_MessageNew( "repeat" , buffer ) );
1343 message_child = vlm_MessageAdd( message_schedule , vlm_MessageNew( "commands" , NULL ) );
1345 for( i=0 ; i < (schedule->i_command) ; i++ )
1347 vlm_MessageAdd( message_child , vlm_MessageNew( schedule->command[i] , NULL ) );
1353 else if( psz_filter && strcmp( psz_filter , "media") == 0 )
1356 vlm_message_t *message;
1357 vlm_message_t *message_child;
1359 message = vlm_MessageNew( "show" , NULL );
1360 message_child = vlm_MessageAdd( message , vlm_MessageNew( "media" , NULL ) );
1362 for( i = 0; i < vlm->i_media; i++ )
1364 vlm_media_t *m = vlm->media[i];
1365 vlm_message_t *message_media = vlm_MessageAdd( message_child , vlm_MessageNew( m->psz_name , NULL ) );
1367 if( m->i_type == VOD_TYPE )
1369 vlm_MessageAdd( message_media , vlm_MessageNew( "type" , "vod" ) );
1373 vlm_MessageAdd( message_media , vlm_MessageNew( "type" , "broadcast" ) );
1376 if( m->b_enabled == VLC_TRUE )
1378 vlm_MessageAdd( message_media , vlm_MessageNew( "enabled" , "yes" ) );
1382 vlm_MessageAdd( message_media , vlm_MessageNew( "enabled" , "no" ) );
1385 if( m->p_input != NULL )
1389 var_Get( m->p_input, "state", &val );
1391 if( val.i_int == PLAYING_S )
1393 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "playing" ) );
1395 else if( val.i_int == PAUSE_S )
1397 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "paused" ) );
1401 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "stop" ) );
1406 vlm_MessageAdd( message_media , vlm_MessageNew( "state" , "stop" ) );
1412 else if( psz_filter && strcmp( psz_filter , "schedule") == 0 )
1415 vlm_message_t *message;
1416 vlm_message_t *message_child;
1418 message = vlm_MessageNew( "show" , NULL );
1419 message_child = vlm_MessageAdd( message , vlm_MessageNew( "schedule" , NULL ) );
1421 for( i = 0; i < vlm->i_schedule; i++ )
1423 vlm_schedule_t *s = vlm->schedule[i];
1424 vlm_message_t *message_schedule = vlm_MessageAdd( message_child , vlm_MessageNew( s->psz_name , NULL ) );
1426 if( s->b_enabled == VLC_TRUE )
1429 mtime_t i_next_date;
1431 vlm_MessageAdd( message_schedule , vlm_MessageNew( "enabled" , "yes" ) );
1433 /* calculate next date */
1436 i_next_date = s->i_date;
1438 if( s->i_period != 0 )
1441 while( s->i_date + j * s->i_period <= i_time && s->i_repeat > j )
1446 i_next_date = s->i_date + j * s->i_period;
1449 if( i_next_date > i_time )
1451 time_t i_date = (time_t) (i_next_date / 1000000) ;
1455 ctime_r( &i_date, psz_date );
1457 char *psz_date = ctime( &i_date );
1460 vlm_MessageAdd( message_schedule , vlm_MessageNew( "next launch" , psz_date ) );
1465 vlm_MessageAdd( message_schedule , vlm_MessageNew( "enabled" , "no" ) );
1471 else if( psz_filter == NULL && media == NULL && schedule == NULL )
1473 vlm_message_t *show1 = vlm_Show( vlm, NULL, NULL, "media" );
1474 vlm_message_t *show2 = vlm_Show( vlm, NULL, NULL, "schedule" );
1476 vlm_MessageAdd( show1 , show2->child[0] );
1478 /* we must destroy the parent node "show" of show2, and not the children */
1479 free( show2->psz_name );
1486 return vlm_MessageNew( "show" , NULL );
1490 static vlm_message_t *vlm_Help( vlm_t *vlm, char *psz_filter )
1492 vlm_message_t *message;
1494 if( psz_filter == NULL )
1498 "\n new (name) vod|broadcast|schedule [properties]"
1499 "\n setup (name) (properties)"
1500 "\n show [(name)|media|schedule]"
1501 "\n del (name)|all|media|schedule"
1502 "\n control (name) (command)"
1503 "\n save (config_file)"
1504 "\n load (config_file)"
1505 "\nMedia Proprieties Syntax:"
1506 "\n input (input_name)"
1507 "\n output (output_name)"
1508 "\n option (option_name)[=value]"
1509 "\n enabled|disabled"
1510 "\n loop|unloop (broadcast only)"
1511 "\nSchedule Proprieties Syntax:"
1512 "\n enabled|disabled"
1513 "\n append (command_until_rest_of_the_line)"
1514 "\n date (year)/(month)/(day)-(hour):(minutes):(seconds)|now"
1515 "\n period (years_aka_12_months)/(months_aka_30_days)/(days)-(hours):(minutes):(seconds)"
1516 "\n repeat (number_of_repetitions)"
1517 "\nControl Commands Syntax:"
1518 "\n play\n pause\n stop\n seek (percentage)\n" );
1520 message = vlm_MessageNew( "help" , NULL );
1521 vlm_MessageAdd( message , vlm_MessageNew( "Help" , help ) );
1526 return vlm_MessageNew( "help" , NULL );
1529 /* file must end by '\0' */
1530 static int vlm_Load( vlm_t *vlm, char *file )
1534 while( *pf != '\0' )
1536 vlm_message_t *message = NULL;
1540 while( pf[i_temp] != '\n' && pf[i_temp] != '\0' && pf[i_temp] != '\r' )
1545 if( pf[i_temp] == '\r' || pf[i_temp] == '\n' )
1548 i_next = i_temp + 1;
1555 if( ExecuteCommand( vlm, pf, &message ) )
1567 static char *vlm_Save( vlm_t *vlm )
1574 for( i = 0; i < vlm->i_media; i++ )
1576 vlm_media_t *media = vlm->media[i];
1578 if( media->i_type == VOD_TYPE )
1580 i_length += strlen( "new vod " ) + strlen(media->psz_name);
1584 i_length += strlen( "new broadcast " ) + strlen(media->psz_name);
1587 if( media->b_enabled == VLC_TRUE )
1589 i_length += strlen( "enabled" );
1593 i_length += strlen( "disabled" );
1596 if( media->b_loop == VLC_TRUE )
1598 i_length += strlen( " loop\n" );
1602 i_length += strlen( "\n" );
1605 for( j = 0; j < media->i_input; j++ )
1607 i_length += strlen( "setup input \"\"\n" ) + strlen( media->psz_name ) + strlen( media->input[j] );
1610 if( media->psz_output != NULL )
1612 i_length += strlen(media->psz_name) + strlen(media->psz_output) + strlen( "setup output \n" );
1615 for( j=0 ; j < media->i_option ; j++ )
1617 i_length += strlen(media->psz_name) + strlen(media->option[j]) + strlen("setup option \n");
1621 for( i = 0; i < vlm->i_schedule; i++ )
1623 vlm_schedule_t *schedule = vlm->schedule[i];
1625 i_length += strlen( "new schedule " ) + strlen( schedule->psz_name );
1627 if( schedule->b_enabled == VLC_TRUE )
1629 i_length += strlen( "date //-:: enabled\n" ) + 14;
1633 i_length += strlen( "date //-:: disabled\n" ) + 14;
1637 if( schedule->i_period != 0 )
1639 i_length += strlen( "setup " ) + strlen( schedule->psz_name ) + strlen( "period //-::\n" ) + 14;
1642 if( schedule->i_repeat >= 0 )
1646 sprintf( buffer, "%d", schedule->i_repeat );
1647 i_length += strlen( "setup repeat \n" ) + strlen( schedule->psz_name ) + strlen( buffer );
1654 for( j = 0; j < schedule->i_command; j++ )
1656 i_length += strlen( "setup append \n" ) + strlen( schedule->psz_name ) + strlen( schedule->command[j] );
1661 /* Don't forget the '\0' */
1663 /* now we have the length of save */
1665 p = save = malloc( i_length );
1668 /* finally we can write in it */
1669 for( i = 0; i < vlm->i_media; i++ )
1671 vlm_media_t *media = vlm->media[i];
1673 if( media->i_type == VOD_TYPE )
1675 p += sprintf( p, "new %s vod ", media->psz_name);
1679 p += sprintf( p, "new %s broadcast ", media->psz_name);
1682 if( media->b_enabled == VLC_TRUE )
1684 p += sprintf( p, "enabled" );
1688 p += sprintf( p, "disabled" );
1691 if( media->b_loop == VLC_TRUE )
1693 p += sprintf( p, " loop\n" );
1697 p += sprintf( p, "\n" );
1700 for( j = 0; j < media->i_input; j++ )
1702 p += sprintf( p, "setup %s input \"%s\"\n", media->psz_name, media->input[j] );
1705 if( media->psz_output != NULL )
1707 p += sprintf( p, "setup %s output %s\n", media->psz_name, media->psz_output );
1710 for( j = 0; j < media->i_option; j++ )
1712 p += sprintf( p, "setup %s option %s\n", media->psz_name, media->option[j] );
1716 /* and now, the schedule scripts */
1718 for( i = 0; i < vlm->i_schedule; i++ )
1720 vlm_schedule_t *schedule = vlm->schedule[i];
1722 time_t i_time = (time_t) ( schedule->i_date / 1000000 );
1724 #ifdef HAVE_LOCALTIME_R
1725 localtime_r( &i_time, &date);
1727 struct tm *p_date = localtime( &i_time );
1731 p += sprintf( p, "new %s schedule ", schedule->psz_name);
1733 if( schedule->b_enabled == VLC_TRUE )
1735 p += sprintf( p, "date %d/%d/%d-%d:%d:%d enabled\n",
1736 date.tm_year + 1900, date.tm_mon + 1, date.tm_mday,
1737 date.tm_hour, date.tm_min, date.tm_sec );
1741 p += sprintf( p, "date %d/%d/%d-%d:%d:%d disabled\n",
1742 date.tm_year + 1900, date.tm_mon + 1, date.tm_mday,
1743 date.tm_hour, date.tm_min, date.tm_sec);
1747 if( schedule->i_period != 0 )
1749 p += sprintf( p, "setup %s ", schedule->psz_name );
1751 i_time = (time_t) ( schedule->i_period / 1000000 );
1753 date.tm_sec = (int)( i_time % 60 );
1754 i_time = i_time / 60;
1755 date.tm_min = (int)( i_time % 60 );
1756 i_time = i_time / 60;
1757 date.tm_hour = (int)( i_time % 24 );
1758 i_time = i_time / 24;
1759 date.tm_mday = (int)( i_time % 30 );
1760 i_time = i_time / 30;
1761 /* okay, okay, months are not always 30 days long */
1762 date.tm_mon = (int)( i_time % 12 );
1763 i_time = i_time / 12;
1764 date.tm_year = (int)i_time;
1766 p += sprintf( p, "period %d/%d/%d-%d:%d:%d\n", date.tm_year ,
1774 if( schedule->i_repeat >= 0 )
1776 p += sprintf( p, "setup %s repeat %d\n", schedule->psz_name, schedule->i_repeat );
1780 p += sprintf( p, "\n" );
1783 for( j = 0; j < schedule->i_command; j++ )
1785 p += sprintf( p, "setup %s append %s\n", schedule->psz_name, schedule->command[j] );
1793 static vlm_schedule_t *vlm_ScheduleNew( vlm_t *vlm , char *psz_name )
1795 vlm_schedule_t *sched= malloc( sizeof( vlm_schedule_t ));
1797 sched->psz_name = strdup( psz_name );
1798 sched->b_enabled = VLC_FALSE;
1799 sched->i_command = 0;
1800 sched->command = NULL;
1802 sched->i_period = 0;
1803 sched->i_repeat = -1;
1805 TAB_APPEND( vlm->i_schedule , vlm->schedule , sched );
1810 /* for now, simple delete. After, del with options (last arg) */
1811 static int vlm_ScheduleDelete( vlm_t *vlm, vlm_schedule_t *sched, char *psz_name )
1820 TAB_REMOVE( vlm->i_schedule, vlm->schedule , sched );
1822 if( vlm->i_schedule == 0 && vlm->schedule ) free( vlm->schedule );
1824 free( sched->psz_name );
1826 for( i = 0; i < sched->i_command; i++ )
1828 free( sched->command[i] );
1836 static vlm_schedule_t *vlm_ScheduleSearch( vlm_t *vlm, char *psz_name )
1840 for( i = 0; i < vlm->i_schedule; i++ )
1842 if( strcmp( psz_name, vlm->schedule[i]->psz_name ) == 0 )
1844 return vlm->schedule[i];
1851 /* Ok, setup schedule command will be able to support only one (argument value) at a time */
1852 static int vlm_ScheduleSetup( vlm_schedule_t *schedule, char *psz_cmd, char *psz_value )
1854 if( strcmp( psz_cmd, "enabled" ) == 0 )
1856 schedule->b_enabled = VLC_TRUE;
1858 else if( strcmp( psz_cmd, "disabled" ) == 0 )
1860 schedule->b_enabled = VLC_FALSE;
1862 else if( strcmp( psz_cmd, "date" ) == 0 )
1868 time.tm_sec = 0; /* seconds */
1869 time.tm_min = 0; /* minutes */
1870 time.tm_hour = 0; /* hours */
1871 time.tm_mday = 0; /* day of the month */
1872 time.tm_mon = 0; /* month */
1873 time.tm_year = 0; /* year */
1874 time.tm_wday = 0; /* day of the week */
1875 time.tm_yday = 0; /* day in the year */
1876 time.tm_isdst = 0; /* daylight saving time */
1878 /* date should be year/month/day-hour:minutes:seconds */
1879 p = strchr( psz_value , '-' );
1881 if( strcmp( psz_value, "now" ) == 0 )
1883 schedule->i_date = 0;
1885 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 */
1893 switch( sscanf( p + 1, "%d:%d:%d" , &i, &j, &k ) )
1913 switch( sscanf( psz_value, "%d/%d/%d" , &i, &j, &k ) )
1919 time.tm_mon = i - 1;
1923 time.tm_year = i - 1900;
1924 time.tm_mon = j - 1;
1931 date = mktime( &time );
1932 schedule->i_date = ((mtime_t) date) * 1000000;
1935 else if( strcmp( psz_cmd, "period" ) == 0 )
1939 char *psz_time = NULL, *psz_date = NULL;
1943 /* First, if date or period are modified, repeat should be equal to -1 */
1944 schedule->i_repeat = -1;
1946 time.tm_sec = 0; /* seconds */
1947 time.tm_min = 0; /* minutes */
1948 time.tm_hour = 0; /* hours */
1949 time.tm_mday = 0; /* day of the month */
1950 time.tm_mon = 0; /* month */
1951 time.tm_year = 0; /* year */
1952 time.tm_wday = 0; /* day of the week */
1953 time.tm_yday = 0; /* day in the year */
1954 time.tm_isdst = 0; /* daylight saving time */
1956 /* date should be year/month/day-hour:minutes:seconds */
1957 p = strchr( psz_value , '-' );
1960 psz_date = psz_value;
1967 psz_time = psz_value;
1971 switch( sscanf( psz_time, "%d:%d:%d" , &i, &j, &k ) )
1990 switch( sscanf( psz_date, "%d/%d/%d" , &i, &j, &k ) )
2009 /* ok, that's stupid... who is going to schedule streams every 42 years ? */
2010 date = (((( time.tm_year * 12 + time.tm_mon ) * 30 + time.tm_mday ) * 24 + time.tm_hour ) * 60 + time.tm_min ) * 60 + time.tm_sec ;
2011 schedule->i_period = ((mtime_t) date) * 1000000;
2013 else if( strcmp( psz_cmd, "repeat" ) == 0 )
2017 if( sscanf( psz_value, "%d" , &i ) == 1 )
2019 schedule->i_repeat = i;
2026 else if( strcmp( psz_cmd, "append" ) == 0 )
2028 char *command = strdup( psz_value );
2030 TAB_APPEND( schedule->i_command, schedule->command, command );
2039 /*****************************************************************************
2041 *****************************************************************************/
2042 static int Manage( vlc_object_t* p_object )
2044 vlm_t *vlm = (vlm_t*)p_object;
2046 mtime_t i_lastcheck;
2049 i_lastcheck = mdate();
2053 while( !vlm->b_die )
2055 vlc_mutex_lock( &vlm->lock );
2057 /* destroy the inputs that wants to die, and launch the next input */
2058 for( i = 0; i < vlm->i_media; i++ )
2060 vlm_media_t *media = vlm->media[i];
2062 if( media->p_input != NULL && ( media->p_input->b_eof || media->p_input->b_error ) )
2064 input_StopThread( media->p_input );
2066 input_DestroyThread( media->p_input );
2067 vlc_object_detach( media->p_input );
2068 vlc_object_destroy( media->p_input );
2069 media->p_input = NULL;
2072 if( media->i_index == media->i_input && media->b_loop == VLC_TRUE )
2077 if( media->i_index < media->i_input )
2081 sprintf( buffer, "%d", media->i_index );
2082 vlm_MediaControl( vlm, media, "play", buffer );
2090 for( i = 0; i < vlm->i_schedule; i++ )
2092 mtime_t i_real_date = vlm->schedule[i]->i_date;
2094 if( vlm->schedule[i]->b_enabled == VLC_TRUE )
2096 if( vlm->schedule[i]->i_date == 0 ) // now !
2098 vlm->schedule[i]->i_date = (i_time / 1000000) * 1000000 ;
2099 i_real_date = i_time;
2101 else if( vlm->schedule[i]->i_period != 0 )
2104 while( vlm->schedule[i]->i_date + j * vlm->schedule[i]->i_period <= i_lastcheck &&
2105 ( vlm->schedule[i]->i_repeat > j || vlm->schedule[i]->i_repeat == -1 ) )
2110 i_real_date = vlm->schedule[i]->i_date + j * vlm->schedule[i]->i_period;
2113 if( i_real_date <= i_time && i_real_date > i_lastcheck )
2115 for( j = 0 ; j < vlm->schedule[i]->i_command ; j++ )
2117 vlm_message_t *message = NULL;
2119 ExecuteCommand( vlm, vlm->schedule[i]->command[j] , &message );
2121 /* for now, drop the message */
2128 i_lastcheck = i_time;
2130 vlc_mutex_unlock( &vlm->lock );
2139 static vlm_message_t* vlm_MessageNew( char *psz_name , char *psz_value )
2141 vlm_message_t *message = malloc( sizeof(vlm_message_t) );
2145 message->psz_name = strdup( psz_name );
2154 message->psz_value = strdup( psz_value );
2158 message->psz_value = NULL;
2161 message->i_child = 0;
2162 message->child = NULL;
2167 void vlm_MessageDelete( vlm_message_t* message )
2171 if( message->psz_name ) free( message->psz_name );
2172 if( message->psz_value ) free( message->psz_value );
2174 for( i = 0; i < message->i_child; i++)
2176 vlm_MessageDelete( message->child[i] );
2183 static vlm_message_t* vlm_MessageAdd( vlm_message_t* message , vlm_message_t* child )
2185 if( message == NULL ) return NULL;
2189 TAB_APPEND( message->i_child , message->child , child );