]> git.sesse.net Git - vlc/blob - modules/control/rc/rc.c
95ef652d7349e235ec29643525779a29bffbd192
[vlc] / 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.5 2002/09/30 11:05:37 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 /*****************************************************************************
61  * Module descriptor
62  *****************************************************************************/
63 #define POS_TEXT N_("show stream position")
64 #define POS_LONGTEXT N_("Show the current position in seconds within the stream from time to time.")
65
66 #define TTY_TEXT N_("fake TTY")
67 #define TTY_LONGTEXT N_("Force the rc plugin to use stdin as if it was a TTY.")
68
69 vlc_module_begin();
70     add_category_hint( N_("Remote control"), NULL );
71     add_bool( "rc-show-pos", 0, NULL, POS_TEXT, POS_LONGTEXT );
72     add_bool( "fake-tty", 0, NULL, TTY_TEXT, TTY_LONGTEXT );
73     set_description( _("remote control interface module") );
74     set_capability( "interface", 20 );
75     set_callbacks( Activate, NULL );
76 vlc_module_end();
77
78 /*****************************************************************************
79  * Activate: initialize and create stuff
80  *****************************************************************************/
81 static int Activate( vlc_object_t *p_this )
82 {
83     intf_thread_t *p_intf = (intf_thread_t*)p_this;
84
85 #ifdef HAVE_ISATTY
86     /* Check that stdin is a TTY */
87     if( !config_GetInt( p_intf, "fake-tty" ) && !isatty( 0 ) )
88     {
89         msg_Warn( p_intf, "fd 0 is not a TTY" );
90         return 1;
91     }
92 #endif
93
94     /* Non-buffered stdout */
95     setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
96
97     p_intf->pf_run = Run;
98
99 #ifdef WIN32
100     AllocConsole();
101     freopen( "CONOUT$", "w", stdout );
102     freopen( "CONOUT$", "w", stderr );
103     freopen( "CONIN$", "r", stdin );
104     printf( VERSION_MESSAGE "\n" );
105 #endif
106
107     printf( "remote control interface initialized, `h' for help\n" );
108     return 0;
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_complete = 0;
124     vlc_bool_t b_showpos = config_GetInt( p_intf, "rc-show-pos" );
125     input_info_category_t * p_category;
126     input_info_t * p_info;
127
128     int        i_dummy;
129     off_t      i_oldpos = 0;
130     off_t      i_newpos;
131     fd_set     fds;                                        /* stdin changed? */
132     struct timeval tv;                                   /* how long to wait */
133
134     double     f_ratio = 1;
135
136     p_input = NULL;
137     p_playlist = NULL;
138
139     while( !p_intf->b_die )
140     {
141         b_complete = 0;
142
143         /* Check stdin */
144         tv.tv_sec = 0;
145         tv.tv_usec = 50000;
146         FD_ZERO( &fds );
147         FD_SET( STDIN_FILENO, &fds );
148
149         i_dummy = select( 32, &fds, NULL, NULL, &tv );
150         if( i_dummy > 0 )
151         {
152             int i_size = 0;
153
154             while( !p_intf->b_die
155                     && i_size < MAX_LINE_LENGTH
156                     && read( STDIN_FILENO, p_buffer + i_size, 1 ) > 0
157                     && p_buffer[ i_size ] != '\r'
158                     && p_buffer[ i_size ] != '\n' )
159             {
160                 i_size++;
161             }
162
163             if( i_size == MAX_LINE_LENGTH
164                  || p_buffer[ i_size ] == '\r'
165                  || p_buffer[ i_size ] == '\n' )
166             {
167                 p_buffer[ i_size ] = 0;
168                 b_complete = 1;
169             }
170         }
171
172         /* Manage the input part */
173         if( p_input == NULL )
174         {
175             if( p_playlist )
176             {
177                 p_input = vlc_object_find( p_playlist, VLC_OBJECT_INPUT,
178                                                        FIND_CHILD );
179             }
180             else
181             {
182                 p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
183                                                    FIND_ANYWHERE );
184                 //if( p_input )
185                 {
186                     p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
187                                                            FIND_PARENT );
188                 }
189             }
190         }
191         else if( p_input->b_dead )
192         {
193             vlc_object_release( p_input );
194             p_input = NULL;
195         }
196
197         if( p_input && b_showpos )
198         {
199             /* Get position */
200             vlc_mutex_lock( &p_input->stream.stream_lock );
201             if( !p_input->b_die && p_input->stream.i_mux_rate )
202             {
203 #define A p_input->stream.p_selected_area
204                 f_ratio = 1.0 / ( 50 * p_input->stream.i_mux_rate );
205                 i_newpos = A->i_tell * f_ratio;
206
207                 if( i_oldpos != i_newpos )
208                 {
209                     i_oldpos = i_newpos;
210                     printf( "pos: %li s / %li s\n", (long int)i_newpos,
211                             (long int)(f_ratio * A->i_size) );
212                 }
213 #undef S
214             }
215             vlc_mutex_unlock( &p_input->stream.stream_lock );
216         }
217
218         /* Is there something to do? */
219         if( b_complete == 1 )
220         {
221             char *p_cmd = p_buffer;
222             char *p_tmp;
223
224             if( !strcmp( p_cmd, "quit" ) )
225             {
226                 p_intf->p_vlc->b_die = VLC_TRUE;
227             }
228             else if( !strcmp( p_cmd, "segfault" ) )
229             {
230                 raise( SIGSEGV );
231             }
232             else if( !strcmp( p_cmd, "prev" ) )
233             {
234                 if( p_playlist ) playlist_Prev( p_playlist );
235             }
236             else if( !strcmp( p_cmd, "next" ) )
237             {
238                 if( p_playlist ) playlist_Next( p_playlist );
239             }
240             else if( !strcmp( p_cmd, "play" ) )
241             {
242                 if( p_playlist ) playlist_Play( p_playlist );
243             }
244             else if( !strcmp( p_cmd, "stop" ) )
245             {
246                 if( p_playlist ) playlist_Stop( p_playlist );
247             }
248             else if( !strcmp( p_cmd, "pause" ) )
249             {
250                 if( p_input ) input_SetStatus( p_input, INPUT_STATUS_PAUSE );
251             }
252             else if( !strcmp( p_cmd, "tree" ) )
253             {
254                 vlc_dumpstructure( p_intf->p_vlc );
255             }
256             else if( !strcmp( p_cmd, "list" ) )
257             {
258                 vlc_liststructure( p_intf->p_vlc );
259             }
260             else if( !strncmp( p_cmd, "set ", 4 ) )
261             {
262 //                vlc_set_r( p_intf->p_vlc, p_cmd + 4, strstr( p_cmd + 4, " " ) );
263                 p_tmp = strstr( p_cmd + 4, " " );
264                 p_tmp[0] = '\0';
265                 config_PutPsz( p_intf->p_vlc, p_cmd + 4, p_tmp + 1 );
266                 config_PutInt( p_intf->p_vlc, p_cmd + 4, atoi(p_tmp + 1) );
267             }
268             else if( !strncmp( p_cmd, "intf ", 5 ) )
269             {
270                 intf_thread_t *p_newintf;
271                 char *psz_oldmodule = config_GetPsz( p_intf->p_vlc, "intf" );
272
273                 config_PutPsz( p_intf->p_vlc, "intf", p_cmd + 5 );
274                 p_newintf = intf_Create( p_intf->p_vlc );
275                 config_PutPsz( p_intf->p_vlc, "intf", psz_oldmodule );
276
277                 if( psz_oldmodule )
278                 {
279                     free( psz_oldmodule );
280                 }
281
282                 if( p_newintf )
283                 {
284                     p_newintf->b_block = VLC_FALSE;
285                     if( intf_RunThread( p_newintf ) )
286                     {
287                         vlc_object_detach( p_newintf );
288                         intf_Destroy( p_newintf );
289                     }
290                 }
291             }
292             else if( !strcmp( p_cmd, "info" ) )
293             {
294                 if ( p_input )
295                 {
296                     vlc_mutex_lock( &p_input->stream.stream_lock );
297                     p_category = p_input->stream.p_info;
298                     while ( p_category )
299                     {
300                         printf( "+----[ %s ]\n", p_category->psz_name );
301                         printf( "| \n" );
302                         p_info = p_category->p_info;
303                         while ( p_info )
304                         {
305                             printf( "| %s: %s\n", p_info->psz_name,
306                                     p_info->psz_value );
307                             p_info = p_info->p_next;
308                         }
309                         p_category = p_category->p_next;
310                         printf( "| \n" );
311                     }
312                     printf( "+----[ end of stream info ]\n" );
313                     vlc_mutex_unlock( &p_input->stream.stream_lock );
314                 }
315                 else
316                 {
317                     printf( "no input\n" );
318                 }
319             }
320             else switch( p_cmd[0] )
321             {
322             case 'a':
323             case 'A':
324                 if( p_cmd[1] == ' ' && p_playlist )
325                 {
326                     playlist_Add( p_playlist, p_cmd + 2,
327                                   PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
328                 }
329                 break;
330
331             case 'f':
332             case 'F':
333                 if( p_input )
334                 {
335                     vout_thread_t *p_vout;
336                     p_vout = vlc_object_find( p_input,
337                                               VLC_OBJECT_VOUT, FIND_CHILD );
338
339                     if( p_vout )
340                     {
341                         p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
342                         vlc_object_release( p_vout );
343                     }
344                 }
345                 break;
346
347             case 's':
348             case 'S':
349                 ;
350                 break;
351
352             case 'r':
353             case 'R':
354                 if( p_input )
355                 {
356                     for( i_dummy = 1;
357                          i_dummy < MAX_LINE_LENGTH && p_cmd[ i_dummy ] >= '0'
358                                                    && p_cmd[ i_dummy ] <= '9';
359                          i_dummy++ )
360                     {
361                         ;
362                     }
363
364                     p_cmd[ i_dummy ] = 0;
365                     input_Seek( p_input, (off_t)atoi( p_cmd + 1 ),
366                                 INPUT_SEEK_SECONDS | INPUT_SEEK_SET );
367                     /* rcreseek(f_cpos); */
368                 }
369                 break;
370
371             case '?':
372             case 'h':
373             case 'H':
374                 printf("+----[ remote control commands ]\n");
375                 printf("| \n");
376                 printf("| a XYZ  . . . . . . . . . . . add XYZ to playlist\n");
377                 printf("| play . . . . . . . . . . . . . . . . play stream\n");
378                 printf("| stop . . . . . . . . . . . . . . . . stop stream\n");
379                 printf("| next . . . . . . . . . . . .  next playlist item\n");
380                 printf("| prev . . . . . . . . . .  previous playlist item\n");
381                 printf("| \n");
382                 printf("| r X  . . . seek in seconds, for instance `r 3.5'\n");
383                 printf("| pause  . . . . . . . . . . . . . .  toggle pause\n");
384                 printf("| f  . . . . . . . . . . . . . . toggle fullscreen\n");
385                 printf("| info . . .  information about the current stream\n");
386                 printf("| \n");
387                 printf("| help . . . . . . . . . . . . . this help message\n");
388                 printf("| quit . . . . . . . . . . . . . . . . .  quit vlc\n");
389                 printf("| \n");
390                 printf("+----[ end of help ]\n");
391                 break;
392             case '\0':
393                 /* Ignore empty lines */
394                 break;
395             default:
396                 printf( "unknown command `%s', type `help' for help\n", p_cmd );
397                 break;
398             }
399         }
400
401         msleep( INTF_IDLE_SLEEP );
402     }
403
404     if( p_input )
405     {
406         vlc_object_release( p_input );
407         p_input = NULL;
408     }
409
410     if( p_playlist )
411     {
412         vlc_object_release( p_playlist );
413         p_playlist = NULL;
414     }
415 }
416