]> git.sesse.net Git - vlc/blob - plugins/text/rc.c
* ALL: changed "struct foo_s" into "struct foo_t" to make greppers happy.
[vlc] / plugins / text / 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.22 2002/07/20 18:01:43 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
34 #include <vlc/vlc.h>
35 #include <vlc/intf.h>
36 #include <vlc/vout.h>
37
38 #ifdef HAVE_UNISTD_H
39 #    include <unistd.h>
40 #endif
41
42 #ifdef HAVE_SYS_TIME_H
43 #    include <sys/time.h>
44 #endif
45 #include <sys/types.h>
46
47 #if defined( WIN32 )
48 #include <winsock2.h>                                            /* select() */
49 #endif
50
51 /*****************************************************************************
52  * intf_sys_t: description and status of rc interface
53  *****************************************************************************/
54 struct intf_sys_t
55 {
56     input_thread_t * p_input;
57 };
58
59 #define MAX_LINE_LENGTH 256
60
61 /*****************************************************************************
62  * Local prototypes.
63  *****************************************************************************/
64 static void intf_getfunctions ( function_list_t * p_function_list );
65 static int  intf_Open         ( intf_thread_t *p_intf );
66 static void intf_Close        ( intf_thread_t *p_intf );
67 static void intf_Run          ( intf_thread_t *p_intf );
68
69 /*****************************************************************************
70  * Build configuration tree.
71  *****************************************************************************/
72 MODULE_CONFIG_START
73 MODULE_CONFIG_STOP
74
75 MODULE_INIT_START
76     SET_DESCRIPTION( _("remote control interface module") )
77     ADD_CAPABILITY( INTF, 20 )
78 MODULE_INIT_STOP
79
80 MODULE_ACTIVATE_START
81     intf_getfunctions( &p_module->p_functions->intf );
82 MODULE_ACTIVATE_STOP
83
84 MODULE_DEACTIVATE_START
85 MODULE_DEACTIVATE_STOP
86
87 /*****************************************************************************
88  * Functions exported as capabilities. They are declared as static so that
89  * we don't pollute the namespace too much.
90  *****************************************************************************/
91 static void intf_getfunctions( function_list_t * p_function_list )
92 {
93     p_function_list->functions.intf.pf_open  = intf_Open;
94     p_function_list->functions.intf.pf_close = intf_Close;
95     p_function_list->functions.intf.pf_run   = intf_Run;
96 }
97
98 /*****************************************************************************
99  * intf_Open: initialize and create stuff
100  *****************************************************************************/
101 static int intf_Open( intf_thread_t *p_intf )
102 {
103 #ifdef HAVE_ISATTY
104     /* Check that stdin is a TTY */
105     if( !isatty( 0 ) )
106     {
107         msg_Warn( p_intf, "fd 0 is not a TTY" );
108         return 1;
109     }
110 #endif
111
112     /* Non-buffered stdout */
113     setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
114
115     /* Allocate instance and initialize some members */
116     p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) );
117     if( p_intf->p_sys == NULL )
118     {
119         msg_Err( p_intf, "out of memory" );
120         return 1;
121     }
122
123 #ifdef WIN32
124     AllocConsole();
125     freopen( "CONOUT$", "w", stdout );
126     freopen( "CONOUT$", "w", stderr );
127     freopen( "CONIN$", "r", stdin );
128     printf( VERSION_MESSAGE "\n" );
129 #endif
130
131     printf( "remote control interface initialized, `h' for help\n" );
132     return 0;
133 }
134
135 /*****************************************************************************
136  * intf_Close: destroy interface stuff
137  *****************************************************************************/
138 static void intf_Close( intf_thread_t *p_intf )
139 {
140     /* Destroy structure */
141     free( p_intf->p_sys );
142 }
143
144 /*****************************************************************************
145  * intf_Run: rc thread
146  *****************************************************************************
147  * This part of the interface is in a separate thread so that we can call
148  * exec() from within it without annoying the rest of the program.
149  *****************************************************************************/
150 static void intf_Run( intf_thread_t *p_intf )
151 {
152     char       p_buffer[ MAX_LINE_LENGTH + 1 ];
153     vlc_bool_t b_complete = 0;
154
155     int        i_dummy;
156     off_t      i_oldpos = 0;
157     off_t      i_newpos;
158     fd_set     fds;                                        /* stdin changed? */
159     struct timeval tv;                                   /* how long to wait */
160
161     double     f_ratio = 1;
162
163     p_intf->p_sys->p_input = NULL;
164
165     while( !p_intf->b_die )
166     {
167         b_complete = 0;
168
169         /* Check stdin */
170         tv.tv_sec = 0;
171         tv.tv_usec = 50000;
172         FD_ZERO( &fds );
173         FD_SET( STDIN_FILENO, &fds );
174
175         i_dummy = select( 32, &fds, NULL, NULL, &tv );
176         if( i_dummy > 0 )
177         {
178             int i_size = 0;
179
180             while( !p_intf->b_die
181                     && i_size < MAX_LINE_LENGTH
182                     && read( STDIN_FILENO, p_buffer + i_size, 1 ) > 0
183                     && p_buffer[ i_size ] != '\r'
184                     && p_buffer[ i_size ] != '\n' )
185             {
186                 i_size++;
187             }
188
189             if( i_size == MAX_LINE_LENGTH
190                  || p_buffer[ i_size ] == '\r'
191                  || p_buffer[ i_size ] == '\n' )
192             {
193                 p_buffer[ i_size ] = 0;
194                 b_complete = 1;
195             }
196         }
197
198         /* Manage the input part */
199         if( p_intf->p_sys->p_input == NULL )
200         {
201             p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
202                                                               FIND_ANYWHERE );
203         }
204         else if( p_intf->p_sys->p_input->b_dead )
205         {
206             vlc_object_release( p_intf->p_sys->p_input );
207             p_intf->p_sys->p_input = NULL;
208         }
209
210         if( p_intf->p_sys->p_input )
211         {
212             input_thread_t *p_input = p_intf->p_sys->p_input;
213
214             /* Get position */
215             vlc_mutex_lock( &p_input->stream.stream_lock );
216             if( !p_input->b_die && p_input->stream.i_mux_rate )
217             {
218 #define A p_input->stream.p_selected_area
219                 f_ratio = 1.0 / ( 50 * p_input->stream.i_mux_rate );
220                 i_newpos = A->i_tell * f_ratio;
221
222                 if( i_oldpos != i_newpos )
223                 {
224                     i_oldpos = i_newpos;
225                     printf( "pos: %li s / %li s\n", (long int)i_newpos,
226                             (long int)(f_ratio * A->i_size) );
227                 }
228 #undef S
229             }
230             vlc_mutex_unlock( &p_input->stream.stream_lock );
231         }
232
233         /* Is there something to do? */
234         if( b_complete == 1 )
235         {
236             char *p_cmd = p_buffer;
237
238             switch( p_cmd[0] )
239             {
240             case 'a':
241             case 'A':
242                 if( p_cmd[1] == ' ' )
243                 {
244                     playlist_t *p_playlist;
245                     p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
246                                                           FIND_ANYWHERE );
247                     if( p_playlist )
248                     {
249                         playlist_Add( p_playlist, p_cmd + 2,
250                                 PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
251                         vlc_object_release( p_playlist );
252                     }
253                 }
254                 break;
255
256             case 'd':
257             case 'D':
258                 vlc_dumpstructure( p_intf->p_vlc );
259                 break;
260
261             case 'p':
262             case 'P':
263                 if( p_intf->p_sys->p_input )
264                 {
265                     input_SetStatus( p_intf->p_sys->p_input,
266                                      INPUT_STATUS_PAUSE );
267                 }
268                 break;
269
270             case 'f':
271             case 'F':
272                 if( p_intf->p_sys->p_input )
273                 {
274                     vout_thread_t *p_vout;
275                     p_vout = vlc_object_find( p_intf->p_sys->p_input,
276                                               VLC_OBJECT_VOUT, FIND_CHILD );
277
278                     if( p_vout )
279                     {
280                         p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
281                         vlc_object_release( p_vout );
282                     }
283                 }
284                 break;
285
286             case 's':
287             case 'S':
288                 ;
289                 break;
290
291             case 'q':
292             case 'Q':
293                 p_intf->p_vlc->b_die = VLC_TRUE;
294                 break;
295
296             case 'r':
297             case 'R':
298                 if( p_intf->p_sys->p_input )
299                 {
300                     for( i_dummy = 1;
301                          i_dummy < MAX_LINE_LENGTH && p_cmd[ i_dummy ] >= '0'
302                                                    && p_cmd[ i_dummy ] <= '9';
303                          i_dummy++ )
304                     {
305                         ;
306                     }
307
308                     p_cmd[ i_dummy ] = 0;
309                     input_Seek( p_intf->p_sys->p_input,
310                                 (off_t)atoi( p_cmd + 1 ),
311                                 INPUT_SEEK_SECONDS | INPUT_SEEK_SET );
312                     /* rcreseek(f_cpos); */
313                 }
314                 break;
315
316             case '?':
317             case 'h':
318             case 'H':
319                 printf( "help for remote control commands\n" );
320                 printf( "h . . . . . . . . . . . . . . . . . . . . . help\n" );
321                 printf( "a XYZ . . . . . . . . . . append XYZ to playlist\n" );
322                 printf( "p . . . . . . . . . . . . . . . . . toggle pause\n" );
323                 printf( "f . . . . . . . . . . . . . . toggle  fullscreen\n" );
324                 printf( "r X . . . seek in seconds,  for instance `r 3.5'\n" );
325                 printf( "q . . . . . . . . . . . . . . . . . . . . . quit\n" );
326                 printf( "end of help\n" );
327                 break;
328
329             default:
330                 printf( "unknown command `%s'\n", p_cmd );
331                 break;
332             }
333         }
334
335         msleep( INTF_IDLE_SLEEP );
336     }
337
338     if( p_intf->p_sys->p_input )
339     {
340         vlc_object_release( p_intf->p_sys->p_input );
341         p_intf->p_sys->p_input = NULL;
342     }
343
344 }
345