1 /*****************************************************************************
2 * rc.c : remote control stdin/stdout plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: rc.c,v 1.9 2002/10/14 16:46:55 sam Exp $
7 * Authors: Peter Surda <shurdeek@panorama.sth.ac.at>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
30 #include <errno.h> /* ENOMEM */
43 #ifdef HAVE_SYS_TIME_H
44 # include <sys/time.h>
46 #include <sys/types.h>
49 #include <winsock2.h> /* select() */
52 #define MAX_LINE_LENGTH 256
54 /*****************************************************************************
56 *****************************************************************************/
57 static int Activate ( vlc_object_t
* );
58 static void Run ( intf_thread_t
*p_intf
);
60 static int Playlist ( vlc_object_t
*, char *, char * );
61 static int Quit ( vlc_object_t
*, char *, char * );
62 static int Intf ( vlc_object_t
*, char *, char * );
64 /*****************************************************************************
66 *****************************************************************************/
67 #define POS_TEXT N_("show stream position")
68 #define POS_LONGTEXT N_("Show the current position in seconds within the stream from time to time.")
70 #define TTY_TEXT N_("fake TTY")
71 #define TTY_LONGTEXT N_("Force the rc plugin to use stdin as if it was a TTY.")
74 add_category_hint( N_("Remote control"), NULL
);
75 add_bool( "rc-show-pos", 0, NULL
, POS_TEXT
, POS_LONGTEXT
);
77 add_bool( "fake-tty", 0, NULL
, TTY_TEXT
, TTY_LONGTEXT
);
79 set_description( _("remote control interface module") );
80 set_capability( "interface", 20 );
81 set_callbacks( Activate
, NULL
);
84 /*****************************************************************************
85 * Activate: initialize and create stuff
86 *****************************************************************************/
87 static int Activate( vlc_object_t
*p_this
)
89 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
92 /* Check that stdin is a TTY */
93 if( !config_GetInt( p_intf
, "fake-tty" ) && !isatty( 0 ) )
95 msg_Warn( p_intf
, "fd 0 is not a TTY" );
100 /* Non-buffered stdout */
101 setvbuf( stdout
, (char *)NULL
, _IOLBF
, 0 );
103 p_intf
->pf_run
= Run
;
107 printf( "remote control interface initialized, `h' for help\n" );
111 /*****************************************************************************
113 *****************************************************************************
114 * This part of the interface is in a separate thread so that we can call
115 * exec() from within it without annoying the rest of the program.
116 *****************************************************************************/
117 static void Run( intf_thread_t
*p_intf
)
119 input_thread_t
* p_input
;
120 playlist_t
* p_playlist
;
122 char p_buffer
[ MAX_LINE_LENGTH
+ 1 ];
123 vlc_bool_t b_showpos
= config_GetInt( p_intf
, "rc-show-pos" );
124 input_info_category_t
* p_category
;
125 input_info_t
* p_info
;
131 double f_ratio
= 1.0;
136 /* Register commands that will be cleaned up upon object destruction */
137 var_Create( p_intf
, "quit", VLC_VAR_COMMAND
);
138 var_Set( p_intf
, "quit", (vlc_value_t
)(void*)Quit
);
139 var_Create( p_intf
, "intf", VLC_VAR_COMMAND
);
140 var_Set( p_intf
, "intf", (vlc_value_t
)(void*)Intf
);
142 var_Create( p_intf
, "play", VLC_VAR_COMMAND
);
143 var_Set( p_intf
, "play", (vlc_value_t
)(void*)Playlist
);
144 var_Create( p_intf
, "stop", VLC_VAR_COMMAND
);
145 var_Set( p_intf
, "stop", (vlc_value_t
)(void*)Playlist
);
146 var_Create( p_intf
, "pause", VLC_VAR_COMMAND
);
147 var_Set( p_intf
, "pause", (vlc_value_t
)(void*)Playlist
);
148 var_Create( p_intf
, "prev", VLC_VAR_COMMAND
);
149 var_Set( p_intf
, "prev", (vlc_value_t
)(void*)Playlist
);
150 var_Create( p_intf
, "next", VLC_VAR_COMMAND
);
151 var_Set( p_intf
, "next", (vlc_value_t
)(void*)Playlist
);
153 while( !p_intf
->b_die
)
157 vlc_bool_t b_complete
= VLC_FALSE
;
163 FD_SET( STDIN_FILENO
, &fds
);
165 i_dummy
= select( 32, &fds
, NULL
, NULL
, &tv
);
170 while( !p_intf
->b_die
171 && i_size
< MAX_LINE_LENGTH
172 && read( STDIN_FILENO
, p_buffer
+ i_size
, 1 ) > 0
173 && p_buffer
[ i_size
] != '\r'
174 && p_buffer
[ i_size
] != '\n' )
179 if( i_size
== MAX_LINE_LENGTH
180 || p_buffer
[ i_size
] == '\r'
181 || p_buffer
[ i_size
] == '\n' )
183 p_buffer
[ i_size
] = 0;
184 b_complete
= VLC_TRUE
;
188 /* Manage the input part */
189 if( p_input
== NULL
)
193 p_input
= vlc_object_find( p_playlist
, VLC_OBJECT_INPUT
,
198 p_input
= vlc_object_find( p_intf
, VLC_OBJECT_INPUT
,
202 p_playlist
= vlc_object_find( p_input
, VLC_OBJECT_PLAYLIST
,
207 else if( p_input
->b_dead
)
209 vlc_object_release( p_input
);
213 if( p_input
&& b_showpos
)
216 vlc_mutex_lock( &p_input
->stream
.stream_lock
);
217 if( !p_input
->b_die
&& p_input
->stream
.i_mux_rate
)
219 #define A p_input->stream.p_selected_area
220 f_ratio
= 1.0 / ( 50 * p_input
->stream
.i_mux_rate
);
221 i_newpos
= A
->i_tell
* f_ratio
;
223 if( i_oldpos
!= i_newpos
)
226 printf( "pos: %li s / %li s\n", (long int)i_newpos
,
227 (long int)(f_ratio
* A
->i_size
) );
231 vlc_mutex_unlock( &p_input
->stream
.stream_lock
);
234 /* Is there something to do? */
237 char *psz_cmd
, *psz_arg
;
239 /* Skip heading spaces */
241 while( *psz_cmd
== ' ' )
246 /* Split psz_cmd at the first space and make sure that
247 * psz_arg is valid */
248 psz_arg
= strchr( psz_cmd
, ' ' );
252 while( *psz_arg
== ' ' )
262 /* If the user typed a registered local command, try it */
263 if( var_Type( p_intf
, psz_cmd
) == VLC_VAR_COMMAND
)
268 val
.psz_string
= psz_arg
;
269 i_ret
= var_Get( p_intf
, psz_cmd
, &val
);
270 printf( "%s: returned %i (%s)\n",
271 psz_cmd
, i_ret
, vlc_error( i_ret
) );
273 /* Or maybe it's a global command */
274 else if( var_Type( p_intf
->p_libvlc
, psz_cmd
) == VLC_VAR_COMMAND
)
279 val
.psz_string
= psz_arg
;
280 /* FIXME: it's a global command, but we should pass the
281 * local object as an argument, not p_intf->p_libvlc. */
282 i_ret
= var_Get( p_intf
->p_libvlc
, psz_cmd
, &val
);
283 printf( "%s: returned %i (%s)\n",
284 psz_cmd
, i_ret
, vlc_error( i_ret
) );
286 else if( !strcmp( psz_cmd
, "info" ) )
290 vlc_mutex_lock( &p_input
->stream
.stream_lock
);
291 p_category
= p_input
->stream
.p_info
;
294 printf( "+----[ %s ]\n", p_category
->psz_name
);
296 p_info
= p_category
->p_info
;
299 printf( "| %s: %s\n", p_info
->psz_name
,
301 p_info
= p_info
->p_next
;
303 p_category
= p_category
->p_next
;
306 printf( "+----[ end of stream info ]\n" );
307 vlc_mutex_unlock( &p_input
->stream
.stream_lock
);
311 printf( "no input\n" );
314 else switch( psz_cmd
[0] )
318 if( psz_cmd
[1] == ' ' && p_playlist
)
320 playlist_Add( p_playlist
, psz_cmd
+ 2,
321 PLAYLIST_APPEND
| PLAYLIST_GO
, PLAYLIST_END
);
329 vout_thread_t
*p_vout
;
330 p_vout
= vlc_object_find( p_input
,
331 VLC_OBJECT_VOUT
, FIND_CHILD
);
335 p_vout
->i_changes
|= VOUT_FULLSCREEN_CHANGE
;
336 vlc_object_release( p_vout
);
351 i_dummy
< MAX_LINE_LENGTH
&& psz_cmd
[ i_dummy
] >= '0'
352 && psz_cmd
[ i_dummy
] <= '9';
358 psz_cmd
[ i_dummy
] = 0;
359 input_Seek( p_input
, (off_t
)atoi( psz_cmd
+ 1 ),
360 INPUT_SEEK_SECONDS
| INPUT_SEEK_SET
);
361 /* rcreseek(f_cpos); */
368 printf("+----[ remote control commands ]\n");
370 printf("| a XYZ . . . . . . . . . . . add XYZ to playlist\n");
371 printf("| play . . . . . . . . . . . . . . . . play stream\n");
372 printf("| stop . . . . . . . . . . . . . . . . stop stream\n");
373 printf("| next . . . . . . . . . . . . next playlist item\n");
374 printf("| prev . . . . . . . . . . previous playlist item\n");
376 printf("| r X . . . seek in seconds, for instance `r 3.5'\n");
377 printf("| pause . . . . . . . . . . . . . . toggle pause\n");
378 printf("| f . . . . . . . . . . . . . . toggle fullscreen\n");
379 printf("| info . . . information about the current stream\n");
381 printf("| help . . . . . . . . . . . . . this help message\n");
382 printf("| quit . . . . . . . . . . . . . . . . . quit vlc\n");
384 printf("+----[ end of help ]\n");
387 /* Ignore empty lines */
390 printf( "unknown command `%s', type `help' for help\n", psz_cmd
);
398 vlc_object_release( p_input
);
404 vlc_object_release( p_playlist
);
409 static int Playlist( vlc_object_t
*p_this
, char *psz_cmd
, char *psz_arg
)
411 input_thread_t
* p_input
;
412 playlist_t
* p_playlist
;
414 p_input
= vlc_object_find( p_this
, VLC_OBJECT_INPUT
, FIND_ANYWHERE
);
421 /* Parse commands that only require an input */
422 if( !strcmp( psz_cmd
, "pause" ) )
424 input_SetStatus( p_input
, INPUT_STATUS_PAUSE
);
425 vlc_object_release( p_input
);
429 p_playlist
= vlc_object_find( p_input
, VLC_OBJECT_PLAYLIST
,
431 vlc_object_release( p_input
);
438 /* Parse commands that require a playlist */
439 if( !strcmp( psz_cmd
, "prev" ) )
441 playlist_Prev( p_playlist
);
443 else if( !strcmp( psz_cmd
, "next" ) )
445 playlist_Next( p_playlist
);
447 else if( !strcmp( psz_cmd
, "play" ) )
449 playlist_Play( p_playlist
);
451 else if( !strcmp( psz_cmd
, "stop" ) )
453 playlist_Stop( p_playlist
);
459 static int Quit( vlc_object_t
*p_this
, char *psz_cmd
, char *psz_arg
)
461 p_this
->p_vlc
->b_die
= VLC_TRUE
;
465 static int Intf( vlc_object_t
*p_this
, char *psz_cmd
, char *psz_arg
)
467 intf_thread_t
*p_newintf
;
468 char *psz_oldmodule
= config_GetPsz( p_this
->p_vlc
, "intf" );
470 config_PutPsz( p_this
->p_vlc
, "intf", psz_arg
);
471 p_newintf
= intf_Create( p_this
->p_vlc
);
472 config_PutPsz( p_this
->p_vlc
, "intf", psz_oldmodule
);
476 free( psz_oldmodule
);
481 p_newintf
->b_block
= VLC_FALSE
;
482 if( intf_RunThread( p_newintf
) )
484 vlc_object_detach( p_newintf
);
485 intf_Destroy( p_newintf
);
492 static int Signal( vlc_object_t
*p_this
, char *psz_cmd
, char *psz_arg
)
494 raise( atoi(psz_arg
) );