* modules/codec/ffmpeg/*: modified the ffmpeg video codec to use direct
[vlc.git] / modules / control / rc / rc.c
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 $
6  *
7  * Authors: Peter Surda <shurdeek@panorama.sth.ac.at>
8  *
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.
13  * 
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>
29
30 #include <errno.h>                                                 /* ENOMEM */
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <signal.h>
34
35 #include <vlc/vlc.h>
36 #include <vlc/intf.h>
37 #include <vlc/vout.h>
38
39 #ifdef HAVE_UNISTD_H
40 #    include <unistd.h>
41 #endif
42
43 #ifdef HAVE_SYS_TIME_H
44 #    include <sys/time.h>
45 #endif
46 #include <sys/types.h>
47
48 #if defined( WIN32 )
49 #include <winsock2.h>                                            /* select() */
50 #endif
51
52 #define MAX_LINE_LENGTH 256
53
54 /*****************************************************************************
55  * Local prototypes
56  *****************************************************************************/
57 static int  Activate     ( vlc_object_t * );
58 static void Run          ( intf_thread_t *p_intf );
59
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 * );
63
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.")
69
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.")
72
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();
83
84 /*****************************************************************************
85  * Activate: initialize and create stuff
86  *****************************************************************************/
87 static int Activate( vlc_object_t *p_this )
88 {
89     intf_thread_t *p_intf = (intf_thread_t*)p_this;
90
91 #ifdef HAVE_ISATTY
92     /* Check that stdin is a TTY */
93     if( !config_GetInt( p_intf, "fake-tty" ) && !isatty( 0 ) )
94     {
95         msg_Warn( p_intf, "fd 0 is not a TTY" );
96         return VLC_EGENERIC;
97     }
98 #endif
99
100     /* Non-buffered stdout */
101     setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
102
103     p_intf->pf_run = Run;
104
105     CONSOLE_INTRO_MSG;
106
107     printf( "remote control interface initialized, `h' for help\n" );
108     return VLC_SUCCESS;
109 }
110
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 )
118 {
119     input_thread_t * p_input;
120     playlist_t *     p_playlist;
121
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;
126
127     int        i_dummy;
128     off_t      i_oldpos = 0;
129     off_t      i_newpos;
130
131     double     f_ratio = 1.0;
132
133     p_input = NULL;
134     p_playlist = NULL;
135
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 );
141
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 );
152
153     while( !p_intf->b_die )
154     {
155         fd_set         fds;
156         struct timeval tv;
157         vlc_bool_t     b_complete = VLC_FALSE;
158
159         /* Check stdin */
160         tv.tv_sec = 0;
161         tv.tv_usec = 50000;
162         FD_ZERO( &fds );
163         FD_SET( STDIN_FILENO, &fds );
164
165         i_dummy = select( 32, &fds, NULL, NULL, &tv );
166         if( i_dummy > 0 )
167         {
168             int i_size = 0;
169
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' )
175             {
176                 i_size++;
177             }
178
179             if( i_size == MAX_LINE_LENGTH
180                  || p_buffer[ i_size ] == '\r'
181                  || p_buffer[ i_size ] == '\n' )
182             {
183                 p_buffer[ i_size ] = 0;
184                 b_complete = VLC_TRUE;
185             }
186         }
187
188         /* Manage the input part */
189         if( p_input == NULL )
190         {
191             if( p_playlist )
192             {
193                 p_input = vlc_object_find( p_playlist, VLC_OBJECT_INPUT,
194                                                        FIND_CHILD );
195             }
196             else
197             {
198                 p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
199                                                    FIND_ANYWHERE );
200                 if( p_input )
201                 {
202                     p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
203                                                            FIND_PARENT );
204                 }
205             }
206         }
207         else if( p_input->b_dead )
208         {
209             vlc_object_release( p_input );
210             p_input = NULL;
211         }
212
213         if( p_input && b_showpos )
214         {
215             /* Get position */
216             vlc_mutex_lock( &p_input->stream.stream_lock );
217             if( !p_input->b_die && p_input->stream.i_mux_rate )
218             {
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;
222
223                 if( i_oldpos != i_newpos )
224                 {
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) );
228                 }
229 #undef S
230             }
231             vlc_mutex_unlock( &p_input->stream.stream_lock );
232         }
233
234         /* Is there something to do? */
235         if( b_complete )
236         {
237             char *psz_cmd, *psz_arg;
238
239             /* Skip heading spaces */
240             psz_cmd = p_buffer;
241             while( *psz_cmd == ' ' )
242             {
243                 psz_cmd++;
244             }
245
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 )
250             {
251                 *psz_arg++ = 0;
252                 while( *psz_arg == ' ' )
253                 {
254                     psz_arg++;
255                 }
256             }
257             else
258             {
259                 psz_arg = "";
260             }
261
262             /* If the user typed a registered local command, try it */
263             if( var_Type( p_intf, psz_cmd ) == VLC_VAR_COMMAND )
264             {
265                 vlc_value_t val;
266                 int i_ret;
267
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 ) );
272             }
273             /* Or maybe it's a global command */
274             else if( var_Type( p_intf->p_libvlc, psz_cmd ) == VLC_VAR_COMMAND )
275             {
276                 vlc_value_t val;
277                 int i_ret;
278
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 ) );
285             }
286             else if( !strcmp( psz_cmd, "info" ) )
287             {
288                 if ( p_input )
289                 {
290                     vlc_mutex_lock( &p_input->stream.stream_lock );
291                     p_category = p_input->stream.p_info;
292                     while ( p_category )
293                     {
294                         printf( "+----[ %s ]\n", p_category->psz_name );
295                         printf( "| \n" );
296                         p_info = p_category->p_info;
297                         while ( p_info )
298                         {
299                             printf( "| %s: %s\n", p_info->psz_name,
300                                     p_info->psz_value );
301                             p_info = p_info->p_next;
302                         }
303                         p_category = p_category->p_next;
304                         printf( "| \n" );
305                     }
306                     printf( "+----[ end of stream info ]\n" );
307                     vlc_mutex_unlock( &p_input->stream.stream_lock );
308                 }
309                 else
310                 {
311                     printf( "no input\n" );
312                 }
313             }
314             else switch( psz_cmd[0] )
315             {
316             case 'a':
317             case 'A':
318                 if( psz_cmd[1] == ' ' && p_playlist )
319                 {
320                     playlist_Add( p_playlist, psz_cmd + 2,
321                                   PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
322                 }
323                 break;
324
325             case 'f':
326             case 'F':
327                 if( p_input )
328                 {
329                     vout_thread_t *p_vout;
330                     p_vout = vlc_object_find( p_input,
331                                               VLC_OBJECT_VOUT, FIND_CHILD );
332
333                     if( p_vout )
334                     {
335                         p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
336                         vlc_object_release( p_vout );
337                     }
338                 }
339                 break;
340
341             case 's':
342             case 'S':
343                 ;
344                 break;
345
346             case 'r':
347             case 'R':
348                 if( p_input )
349                 {
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++ )
354                     {
355                         ;
356                     }
357
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); */
362                 }
363                 break;
364
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;
392             }
393         }
394     }
395
396     if( p_input )
397     {
398         vlc_object_release( p_input );
399         p_input = NULL;
400     }
401
402     if( p_playlist )
403     {
404         vlc_object_release( p_playlist );
405         p_playlist = NULL;
406     }
407 }
408
409 static int Playlist( vlc_object_t *p_this, char *psz_cmd, char *psz_arg )
410 {
411     input_thread_t * p_input;
412     playlist_t *     p_playlist;
413
414     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
415
416     if( !p_input )
417     {
418         return VLC_ENOOBJ;
419     }
420
421     /* Parse commands that only require an input */
422     if( !strcmp( psz_cmd, "pause" ) )
423     {
424         input_SetStatus( p_input, INPUT_STATUS_PAUSE );
425         vlc_object_release( p_input );
426         return VLC_SUCCESS;
427     }
428
429     p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
430                                            FIND_PARENT );
431     vlc_object_release( p_input );
432
433     if( !p_playlist )
434     {
435         return VLC_ENOOBJ;
436     }
437
438     /* Parse commands that require a playlist */
439     if( !strcmp( psz_cmd, "prev" ) )
440     {
441         playlist_Prev( p_playlist );
442     }
443     else if( !strcmp( psz_cmd, "next" ) )
444     {
445         playlist_Next( p_playlist );
446     }
447     else if( !strcmp( psz_cmd, "play" ) )
448     {
449         playlist_Play( p_playlist );
450     }
451     else if( !strcmp( psz_cmd, "stop" ) )
452     {
453         playlist_Stop( p_playlist );
454     }
455
456     return VLC_SUCCESS;
457 }
458
459 static int Quit( vlc_object_t *p_this, char *psz_cmd, char *psz_arg )
460 {
461     p_this->p_vlc->b_die = VLC_TRUE;
462     return VLC_SUCCESS;
463 }
464
465 static int Intf( vlc_object_t *p_this, char *psz_cmd, char *psz_arg )
466 {
467     intf_thread_t *p_newintf;
468     char *psz_oldmodule = config_GetPsz( p_this->p_vlc, "intf" );
469
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 );
473
474     if( psz_oldmodule )
475     {
476         free( psz_oldmodule );
477     }
478
479     if( p_newintf )
480     {
481         p_newintf->b_block = VLC_FALSE;
482         if( intf_RunThread( p_newintf ) )
483         {
484             vlc_object_detach( p_newintf );
485             intf_Destroy( p_newintf );
486         }
487     }
488
489     return VLC_SUCCESS;
490 }
491
492 static int Signal( vlc_object_t *p_this, char *psz_cmd, char *psz_arg )
493 {
494     raise( atoi(psz_arg) );
495     return VLC_SUCCESS;
496 }
497
498