* ./include/vlc/vlc.h, ./src/libvlc.c: added VLC_Error() to the libvlc API.
[vlc.git] / modules / control / rc / rc.c
blob12dac6bd8c79296acee73c823bcc9e93d06d3884
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 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
28 #include <string.h>
30 #include <errno.h> /* ENOMEM */
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <signal.h>
35 #include <vlc/vlc.h>
36 #include <vlc/intf.h>
37 #include <vlc/vout.h>
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
43 #ifdef HAVE_SYS_TIME_H
44 # include <sys/time.h>
45 #endif
46 #include <sys/types.h>
48 #if defined( WIN32 )
49 #include <winsock2.h> /* select() */
50 #endif
52 #define MAX_LINE_LENGTH 256
54 /*****************************************************************************
55 * Local prototypes
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 /*****************************************************************************
65 * Module descriptor
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.")
73 vlc_module_begin();
74 add_category_hint( N_("Remote control"), NULL );
75 add_bool( "rc-show-pos", 0, NULL, POS_TEXT, POS_LONGTEXT );
76 #ifdef HAVE_ISATTY
77 add_bool( "fake-tty", 0, NULL, TTY_TEXT, TTY_LONGTEXT );
78 #endif
79 set_description( _("remote control interface module") );
80 set_capability( "interface", 20 );
81 set_callbacks( Activate, NULL );
82 vlc_module_end();
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;
91 #ifdef HAVE_ISATTY
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" );
96 return VLC_EGENERIC;
98 #endif
100 /* Non-buffered stdout */
101 setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
103 p_intf->pf_run = Run;
105 CONSOLE_INTRO_MSG;
107 printf( "remote control interface initialized, `h' for help\n" );
108 return VLC_SUCCESS;
111 /*****************************************************************************
112 * Run: rc thread
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;
127 int i_dummy;
128 off_t i_oldpos = 0;
129 off_t i_newpos;
131 double f_ratio = 1.0;
133 p_input = NULL;
134 p_playlist = NULL;
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 )
155 fd_set fds;
156 struct timeval tv;
157 vlc_bool_t b_complete = VLC_FALSE;
159 /* Check stdin */
160 tv.tv_sec = 0;
161 tv.tv_usec = 50000;
162 FD_ZERO( &fds );
163 FD_SET( STDIN_FILENO, &fds );
165 i_dummy = select( 32, &fds, NULL, NULL, &tv );
166 if( i_dummy > 0 )
168 int i_size = 0;
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' )
176 i_size++;
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 )
191 if( p_playlist )
193 p_input = vlc_object_find( p_playlist, VLC_OBJECT_INPUT,
194 FIND_CHILD );
196 else
198 p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
199 FIND_ANYWHERE );
200 if( p_input )
202 p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
203 FIND_PARENT );
207 else if( p_input->b_dead )
209 vlc_object_release( p_input );
210 p_input = NULL;
213 if( p_input && b_showpos )
215 /* Get position */
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 )
225 i_oldpos = i_newpos;
226 printf( "pos: %li s / %li s\n", (long int)i_newpos,
227 (long int)(f_ratio * A->i_size) );
229 #undef S
231 vlc_mutex_unlock( &p_input->stream.stream_lock );
234 /* Is there something to do? */
235 if( b_complete )
237 char *psz_cmd, *psz_arg;
239 /* Skip heading spaces */
240 psz_cmd = p_buffer;
241 while( *psz_cmd == ' ' )
243 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, ' ' );
249 if( psz_arg )
251 *psz_arg++ = 0;
252 while( *psz_arg == ' ' )
254 psz_arg++;
257 else
259 psz_arg = "";
262 /* If the user typed a registered local command, try it */
263 if( var_Type( p_intf, psz_cmd ) == VLC_VAR_COMMAND )
265 vlc_value_t val;
266 int i_ret;
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 )
276 vlc_value_t val;
277 int i_ret;
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" ) )
288 if ( p_input )
290 vlc_mutex_lock( &p_input->stream.stream_lock );
291 p_category = p_input->stream.p_info;
292 while ( p_category )
294 printf( "+----[ %s ]\n", p_category->psz_name );
295 printf( "| \n" );
296 p_info = p_category->p_info;
297 while ( p_info )
299 printf( "| %s: %s\n", p_info->psz_name,
300 p_info->psz_value );
301 p_info = p_info->p_next;
303 p_category = p_category->p_next;
304 printf( "| \n" );
306 printf( "+----[ end of stream info ]\n" );
307 vlc_mutex_unlock( &p_input->stream.stream_lock );
309 else
311 printf( "no input\n" );
314 else switch( psz_cmd[0] )
316 case 'a':
317 case 'A':
318 if( psz_cmd[1] == ' ' && p_playlist )
320 playlist_Add( p_playlist, psz_cmd + 2,
321 PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
323 break;
325 case 'f':
326 case 'F':
327 if( p_input )
329 vout_thread_t *p_vout;
330 p_vout = vlc_object_find( p_input,
331 VLC_OBJECT_VOUT, FIND_CHILD );
333 if( p_vout )
335 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
336 vlc_object_release( p_vout );
339 break;
341 case 's':
342 case 'S':
344 break;
346 case 'r':
347 case 'R':
348 if( p_input )
350 for( i_dummy = 1;
351 i_dummy < MAX_LINE_LENGTH && psz_cmd[ i_dummy ] >= '0'
352 && psz_cmd[ i_dummy ] <= '9';
353 i_dummy++ )
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); */
363 break;
365 case '?':
366 case 'h':
367 case 'H':
368 printf("+----[ remote control commands ]\n");
369 printf("| \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");
375 printf("| \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");
380 printf("| \n");
381 printf("| help . . . . . . . . . . . . . this help message\n");
382 printf("| quit . . . . . . . . . . . . . . . . . quit vlc\n");
383 printf("| \n");
384 printf("+----[ end of help ]\n");
385 break;
386 case '\0':
387 /* Ignore empty lines */
388 break;
389 default:
390 printf( "unknown command `%s', type `help' for help\n", psz_cmd );
391 break;
396 if( p_input )
398 vlc_object_release( p_input );
399 p_input = NULL;
402 if( p_playlist )
404 vlc_object_release( p_playlist );
405 p_playlist = NULL;
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 );
416 if( !p_input )
418 return VLC_ENOOBJ;
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 );
426 return VLC_SUCCESS;
429 p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
430 FIND_PARENT );
431 vlc_object_release( p_input );
433 if( !p_playlist )
435 return VLC_ENOOBJ;
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 );
456 return VLC_SUCCESS;
459 static int Quit( vlc_object_t *p_this, char *psz_cmd, char *psz_arg )
461 p_this->p_vlc->b_die = VLC_TRUE;
462 return VLC_SUCCESS;
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 );
474 if( psz_oldmodule )
476 free( psz_oldmodule );
479 if( p_newintf )
481 p_newintf->b_block = VLC_FALSE;
482 if( intf_RunThread( p_newintf ) )
484 vlc_object_detach( p_newintf );
485 intf_Destroy( p_newintf );
489 return VLC_SUCCESS;
492 static int Signal( vlc_object_t *p_this, char *psz_cmd, char *psz_arg )
494 raise( atoi(psz_arg) );
495 return VLC_SUCCESS;