]> git.sesse.net Git - vlc/blob - plugins/text/rc.c
e0ae2896fa3f01b1eb5b25423eb493f574b6ad19
[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.23 2002/07/21 18:57:02 sigmunau 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     input_info_category_t * p_category;
155     input_info_t * p_info;
156
157     int        i_dummy;
158     off_t      i_oldpos = 0;
159     off_t      i_newpos;
160     fd_set     fds;                                        /* stdin changed? */
161     struct timeval tv;                                   /* how long to wait */
162
163     double     f_ratio = 1;
164     char       psz_dashes[81];
165
166     memset(psz_dashes, '-', 80);
167     psz_dashes[80] = '\0';
168     
169     p_intf->p_sys->p_input = NULL;
170
171     while( !p_intf->b_die )
172     {
173         b_complete = 0;
174
175         /* Check stdin */
176         tv.tv_sec = 0;
177         tv.tv_usec = 50000;
178         FD_ZERO( &fds );
179         FD_SET( STDIN_FILENO, &fds );
180
181         i_dummy = select( 32, &fds, NULL, NULL, &tv );
182         if( i_dummy > 0 )
183         {
184             int i_size = 0;
185
186             while( !p_intf->b_die
187                     && i_size < MAX_LINE_LENGTH
188                     && read( STDIN_FILENO, p_buffer + i_size, 1 ) > 0
189                     && p_buffer[ i_size ] != '\r'
190                     && p_buffer[ i_size ] != '\n' )
191             {
192                 i_size++;
193             }
194
195             if( i_size == MAX_LINE_LENGTH
196                  || p_buffer[ i_size ] == '\r'
197                  || p_buffer[ i_size ] == '\n' )
198             {
199                 p_buffer[ i_size ] = 0;
200                 b_complete = 1;
201             }
202         }
203
204         /* Manage the input part */
205         if( p_intf->p_sys->p_input == NULL )
206         {
207             p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
208                                                               FIND_ANYWHERE );
209         }
210         else if( p_intf->p_sys->p_input->b_dead )
211         {
212             vlc_object_release( p_intf->p_sys->p_input );
213             p_intf->p_sys->p_input = NULL;
214         }
215
216         if( p_intf->p_sys->p_input )
217         {
218             input_thread_t *p_input = p_intf->p_sys->p_input;
219
220             /* Get position */
221             vlc_mutex_lock( &p_input->stream.stream_lock );
222             if( !p_input->b_die && p_input->stream.i_mux_rate )
223             {
224 #define A p_input->stream.p_selected_area
225                 f_ratio = 1.0 / ( 50 * p_input->stream.i_mux_rate );
226                 i_newpos = A->i_tell * f_ratio;
227
228                 if( i_oldpos != i_newpos )
229                 {
230                     i_oldpos = i_newpos;
231                     printf( "pos: %li s / %li s\n", (long int)i_newpos,
232                             (long int)(f_ratio * A->i_size) );
233                 }
234 #undef S
235             }
236             vlc_mutex_unlock( &p_input->stream.stream_lock );
237         }
238
239         /* Is there something to do? */
240         if( b_complete == 1 )
241         {
242             char *p_cmd = p_buffer;
243
244             switch( p_cmd[0] )
245             {
246             case 'a':
247             case 'A':
248                 if( p_cmd[1] == ' ' )
249                 {
250                     playlist_t *p_playlist;
251                     p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
252                                                           FIND_ANYWHERE );
253                     if( p_playlist )
254                     {
255                         playlist_Add( p_playlist, p_cmd + 2,
256                                 PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
257                         vlc_object_release( p_playlist );
258                     }
259                 }
260                 break;
261
262             case 'd':
263             case 'D':
264                 vlc_dumpstructure( p_intf->p_vlc );
265                 break;
266
267             case 'p':
268             case 'P':
269                 if( p_intf->p_sys->p_input )
270                 {
271                     input_SetStatus( p_intf->p_sys->p_input,
272                                      INPUT_STATUS_PAUSE );
273                 }
274                 break;
275
276             case 'f':
277             case 'F':
278                 if( p_intf->p_sys->p_input )
279                 {
280                     vout_thread_t *p_vout;
281                     p_vout = vlc_object_find( p_intf->p_sys->p_input,
282                                               VLC_OBJECT_VOUT, FIND_CHILD );
283
284                     if( p_vout )
285                     {
286                         p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
287                         vlc_object_release( p_vout );
288                     }
289                 }
290                 break;
291
292             case 's':
293             case 'S':
294                 ;
295                 break;
296
297             case 'q':
298             case 'Q':
299                 p_intf->p_vlc->b_die = VLC_TRUE;
300                 break;
301
302             case 'r':
303             case 'R':
304                 if( p_intf->p_sys->p_input )
305                 {
306                     for( i_dummy = 1;
307                          i_dummy < MAX_LINE_LENGTH && p_cmd[ i_dummy ] >= '0'
308                                                    && p_cmd[ i_dummy ] <= '9';
309                          i_dummy++ )
310                     {
311                         ;
312                     }
313
314                     p_cmd[ i_dummy ] = 0;
315                     input_Seek( p_intf->p_sys->p_input,
316                                 (off_t)atoi( p_cmd + 1 ),
317                                 INPUT_SEEK_SECONDS | INPUT_SEEK_SET );
318                     /* rcreseek(f_cpos); */
319                 }
320                 break;
321
322             case '?':
323             case 'h':
324             case 'H':
325                 printf( "help for remote control commands\n" );
326                 printf( "h . . . . . . . . . . . . . . . . . . . . . help\n" );
327                 printf( "a XYZ . . . . . . . . . . append XYZ to playlist\n" );
328                 printf( "p . . . . . . . . . . . . . . . . . toggle pause\n" );
329                 printf( "f . . . . . . . . . . . . . . toggle  fullscreen\n" );
330                 printf( "r X . . . seek in seconds,  for instance `r 3.5'\n" );
331                 printf( "q . . . . . . . . . . . . . . . . . . . . . quit\n" );
332                 printf( "end of help\n" );
333                 break;
334             case 'i':
335             case 'I':
336                 printf( "Dumping stream info\n" );
337                 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
338                 p_category = p_intf->p_sys->p_input->stream.p_info;
339                 while ( p_category )
340                 {
341                     psz_dashes[72 - strlen(p_category->psz_name) ] = '\0';
342                     printf( "+--| %s |%s+\n", p_category->psz_name, psz_dashes);
343                     psz_dashes[72 - strlen(p_category->psz_name) ] = '-';
344                     p_info = p_category->p_info;
345                     while ( p_info )
346                     {
347                         printf( "| %s: %s\n", p_info->psz_name,
348                                 p_info->psz_value );
349                         p_info = p_info->p_next;
350                     }
351                     printf("|\n");
352                     p_category = p_category->p_next;
353                 }
354                 psz_dashes[78] = '\0';
355                 printf( "+%s+\n", psz_dashes );
356                 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
357                 break;
358             default:
359                 printf( "unknown command `%s'\n", p_cmd );
360                 break;
361             }
362         }
363
364         msleep( INTF_IDLE_SLEEP );
365     }
366
367     if( p_intf->p_sys->p_input )
368     {
369         vlc_object_release( p_intf->p_sys->p_input );
370         p_intf->p_sys->p_input = NULL;
371     }
372
373 }
374