* ./src/playlist/playlist.c: lots of playlist behaviour enhancements.
[vlc.git] / 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.18 2002/06/07 14:30:41 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_s
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     /* Non-buffered stdout */
104     setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
105
106     /* Allocate instance and initialize some members */
107     p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) );
108     if( p_intf->p_sys == NULL )
109     {
110         msg_Err( p_intf, "out of memory" );
111         return( 1 );
112     }
113
114 #ifdef WIN32
115     AllocConsole();
116     freopen( "CONOUT$", "w", stdout );
117     freopen( "CONOUT$", "w", stderr );
118     freopen( "CONIN$", "r", stdin );
119     printf( VERSION_MESSAGE "\n" );
120 #endif
121
122     printf( "remote control interface initialized, `h' for help\n" );
123     return( 0 );
124 }
125
126 /*****************************************************************************
127  * intf_Close: destroy interface stuff
128  *****************************************************************************/
129 static void intf_Close( intf_thread_t *p_intf )
130 {
131     /* Destroy structure */
132     free( p_intf->p_sys );
133 }
134
135 /*****************************************************************************
136  * intf_Run: rc thread
137  *****************************************************************************
138  * This part of the interface is in a separate thread so that we can call
139  * exec() from within it without annoying the rest of the program.
140  *****************************************************************************/
141 static void intf_Run( intf_thread_t *p_intf )
142 {
143     char       p_buffer[ MAX_LINE_LENGTH + 1 ];
144     vlc_bool_t b_complete = 0;
145
146     int        i_dummy;
147     off_t      i_oldpos = 0;
148     off_t      i_newpos;
149     fd_set     fds;                                        /* stdin changed? */
150     struct timeval tv;                                   /* how long to wait */
151
152     double     f_ratio = 1;
153
154     p_intf->p_sys->p_input = NULL;
155
156     while( !p_intf->b_die )
157     {
158         b_complete = 0;
159
160         /* Check stdin */
161         tv.tv_sec = 0;
162         tv.tv_usec = 50000;
163         FD_ZERO( &fds );
164         FD_SET( STDIN_FILENO, &fds );
165
166         i_dummy = select( 32, &fds, NULL, NULL, &tv );
167         if( i_dummy > 0 )
168         {
169             int i_size = 0;
170
171             while( !p_intf->b_die
172                     && i_size < MAX_LINE_LENGTH
173                     && read( STDIN_FILENO, p_buffer + i_size, 1 ) > 0
174                     && p_buffer[ i_size ] != '\r'
175                     && p_buffer[ i_size ] != '\n' )
176             {
177                 i_size++;
178             }
179
180             if( i_size == MAX_LINE_LENGTH
181                  || p_buffer[ i_size ] == '\r'
182                  || p_buffer[ i_size ] == '\n' )
183             {
184                 p_buffer[ i_size ] = 0;
185                 b_complete = 1;
186             }
187         }
188
189         /* Manage the input part */
190         if( p_intf->p_sys->p_input == NULL )
191         {
192             p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
193                                                               FIND_ANYWHERE );
194         }
195         else if( p_intf->p_sys->p_input->b_dead )
196         {
197             vlc_object_release( p_intf->p_sys->p_input );
198             p_intf->p_sys->p_input = NULL;
199         }
200
201         if( p_intf->p_sys->p_input )
202         {
203             input_thread_t *p_input = p_intf->p_sys->p_input;
204
205             /* Get position */
206             vlc_mutex_lock( &p_input->stream.stream_lock );
207             if( !p_input->b_die && p_input->stream.i_mux_rate )
208             {
209 #define A p_input->stream.p_selected_area
210                 f_ratio = 1.0 / ( 50 * p_input->stream.i_mux_rate );
211                 i_newpos = A->i_tell * f_ratio;
212
213                 if( i_oldpos != i_newpos )
214                 {
215                     i_oldpos = i_newpos;
216                     printf( "pos: %li s / %li s\n", (long int)i_newpos,
217                             (long int)(f_ratio * A->i_size) );
218                 }
219 #undef S
220             }
221             vlc_mutex_unlock( &p_input->stream.stream_lock );
222         }
223
224         /* Is there something to do? */
225         if( b_complete == 1 )
226         {
227             char *p_cmd = p_buffer;
228
229             switch( p_cmd[0] )
230             {
231             case 'a':
232             case 'A':
233                 if( p_cmd[1] == ' ' )
234                 {
235 //                    playlist_Add( p_intf, PLAYLIST_END, p_cmd + 2 );
236 //                    playlist_Jumpto( p_intf->p_vlc->p_playlist,
237 //                                     p_intf->p_vlc->p_playlist->i_size-2 );
238                 }
239                 break;
240
241             case 'd':
242             case 'D':
243                 vlc_dumpstructure( p_intf->p_vlc );
244                 break;
245
246             case 'p':
247             case 'P':
248                 if( p_intf->p_sys->p_input )
249                 {
250                     input_SetStatus( p_intf->p_sys->p_input,
251                                      INPUT_STATUS_PAUSE );
252                 }
253                 break;
254
255             case 'f':
256             case 'F':
257                 if( p_intf->p_sys->p_input )
258                 {
259                     vout_thread_t *p_vout;
260                     p_vout = vlc_object_find( p_intf->p_sys->p_input,
261                                               VLC_OBJECT_VOUT, FIND_CHILD );
262
263                     if( p_vout )
264                     {
265                         p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
266                         vlc_object_release( p_vout );
267                     }
268                 }
269                 break;
270
271             case 's':
272             case 'S':
273                 ;
274                 break;
275
276             case 'q':
277             case 'Q':
278                 p_intf->p_vlc->b_die = 1;
279                 break;
280
281             case 'r':
282             case 'R':
283                 if( p_intf->p_sys->p_input )
284                 {
285                     for( i_dummy = 1;
286                          i_dummy < MAX_LINE_LENGTH && p_cmd[ i_dummy ] >= '0'
287                                                    && p_cmd[ i_dummy ] <= '9';
288                          i_dummy++ )
289                     {
290                         ;
291                     }
292
293                     p_cmd[ i_dummy ] = 0;
294                     input_Seek( p_intf->p_sys->p_input,
295                                 (off_t)atoi( p_cmd + 1 ),
296                                 INPUT_SEEK_SECONDS | INPUT_SEEK_SET );
297                     /* rcreseek(f_cpos); */
298                 }
299                 break;
300
301             case '?':
302             case 'h':
303             case 'H':
304                 printf( "help for remote control commands\n" );
305                 printf( "h . . . . . . . . . . . . . . . . . . . . . help\n" );
306                 printf( "a XYZ . . . . . . . . . . append XYZ to playlist\n" );
307                 printf( "p . . . . . . . . . . . . . . . . . toggle pause\n" );
308                 printf( "f . . . . . . . . . . . . . . toggle  fullscreen\n" );
309                 printf( "r X . . . seek in seconds,  for instance `r 3.5'\n" );
310                 printf( "q . . . . . . . . . . . . . . . . . . . . . quit\n" );
311                 printf( "end of help\n" );
312                 break;
313
314             default:
315                 printf( "unknown command `%s'\n", p_cmd );
316                 break;
317             }
318         }
319
320         msleep( INTF_IDLE_SLEEP );
321     }
322
323     if( p_intf->p_sys->p_input )
324     {
325         vlc_object_release( p_intf->p_sys->p_input );
326         p_intf->p_sys->p_input = NULL;
327     }
328
329 }
330