]> git.sesse.net Git - vlc/blob - plugins/text/rc.c
* ./BUGS: added a list of known bugs. Please add your findings!
[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.8 2002/01/04 14:01:34 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 <unistd.h>
34 #include <sys/time.h>
35 #include <sys/types.h>
36
37 #include <videolan/vlc.h>
38
39 #if defined( WIN32 )
40 #include <winsock2.h>                                            /* select() */
41 #endif
42
43 #include "stream_control.h"
44 #include "input_ext-intf.h"
45
46 #include "intf_playlist.h"
47 #include "interface.h"
48
49 #include "video.h"
50 #include "video_output.h"
51
52 /*****************************************************************************
53  * intf_sys_t: description and status of rc interface
54  *****************************************************************************/
55 typedef struct intf_sys_s
56 {
57     vlc_mutex_t         change_lock;
58
59 } intf_sys_t;
60
61 #define MAX_LINE_LENGTH 256
62
63 /*****************************************************************************
64  * Local prototypes.
65  *****************************************************************************/
66 static void intf_getfunctions ( function_list_t * p_function_list );
67 static int  intf_Probe        ( probedata_t *p_data );
68 static int  intf_Open         ( intf_thread_t *p_intf );
69 static void intf_Close        ( intf_thread_t *p_intf );
70 static void intf_Run          ( intf_thread_t *p_intf );
71
72 /*****************************************************************************
73  * Build configuration tree.
74  *****************************************************************************/
75 MODULE_CONFIG_START
76 MODULE_CONFIG_STOP
77
78 MODULE_INIT_START
79     SET_DESCRIPTION( "remote control interface module" )
80     ADD_CAPABILITY( INTF, 20 )
81     ADD_SHORTCUT( "rc" )
82 MODULE_INIT_STOP
83
84 MODULE_ACTIVATE_START
85     intf_getfunctions( &p_module->p_functions->intf );
86 MODULE_ACTIVATE_STOP
87
88 MODULE_DEACTIVATE_START
89 MODULE_DEACTIVATE_STOP
90
91 /*****************************************************************************
92  * Functions exported as capabilities. They are declared as static so that
93  * we don't pollute the namespace too much.
94  *****************************************************************************/
95 static void intf_getfunctions( function_list_t * p_function_list )
96 {
97     p_function_list->pf_probe = intf_Probe;
98     p_function_list->functions.intf.pf_open  = intf_Open;
99     p_function_list->functions.intf.pf_close = intf_Close;
100     p_function_list->functions.intf.pf_run   = intf_Run;
101 }
102
103 /*****************************************************************************
104  * intf_Probe: probe the interface and return a score
105  *****************************************************************************
106  * This function tries to initialize rc and returns a score to the
107  * plugin manager so that it can select the best plugin.
108  *****************************************************************************/
109 static int intf_Probe( probedata_t *p_data )
110 {
111     return( 20 );
112 }
113
114 /*****************************************************************************
115  * intf_Open: initialize and create stuff
116  *****************************************************************************/
117 static int intf_Open( intf_thread_t *p_intf )
118 {
119     /* Non-buffered stdout */
120     setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
121
122     /* Allocate instance and initialize some members */
123     p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) );
124     if( p_intf->p_sys == NULL )
125     {
126         intf_ErrMsg( "intf error: %s", strerror(ENOMEM) );
127         return( 1 );
128     }
129
130     intf_Msg( "rc: remote control interface initialized, `h' for help" );
131     return( 0 );
132 }
133
134 /*****************************************************************************
135  * intf_Close: destroy interface stuff
136  *****************************************************************************/
137 static void intf_Close( intf_thread_t *p_intf )
138 {
139     /* Destroy structure */
140     free( p_intf->p_sys );
141 }
142
143 /*****************************************************************************
144  * intf_Run: rc thread
145  *****************************************************************************
146  * This part of the interface is in a separate thread so that we can call
147  * exec() from within it without annoying the rest of the program.
148  *****************************************************************************/
149 static void intf_Run( intf_thread_t *p_intf )
150 {
151     char      p_cmd[ MAX_LINE_LENGTH + 1 ];
152     int       i_cmd_pos;
153     boolean_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_cpos;
162     double    f_ratio = 1;
163
164     while( !p_intf->b_die )
165     {
166 #define S p_intf->p_input->stream
167         if( p_intf->p_input != NULL )
168         {
169             /* Get position */
170             if( S.i_mux_rate )
171             {
172                 f_ratio = 1.0 / ( 50 * S.i_mux_rate );
173                 i_newpos = S.p_selected_area->i_tell * f_ratio;
174
175                 if( i_oldpos != i_newpos )
176                 {
177                     i_oldpos = i_newpos;
178                     intf_Msg( "rc: pos: %li s / %li s", (long int)i_newpos,
179                               (long int)( f_ratio *
180                                           S.p_selected_area->i_size ) );
181                 }
182             }
183         }
184 #undef S
185
186         b_complete = 0;
187         i_cmd_pos = 0;
188
189         /* Check stdin */
190         tv.tv_sec = 0;
191         tv.tv_usec = 50000;
192         FD_ZERO( &fds );
193         FD_SET( STDIN_FILENO, &fds );
194
195         if( select( 32, &fds, NULL, NULL, &tv ) )
196         {
197             while( !p_intf->b_die
198                     && i_cmd_pos < MAX_LINE_LENGTH
199                     && read( STDIN_FILENO, p_cmd + i_cmd_pos, 1 ) > 0
200                     && p_cmd[ i_cmd_pos ] != '\r'
201                     && p_cmd[ i_cmd_pos ] != '\n' )
202             {
203                 i_cmd_pos++;
204             }
205
206             if( i_cmd_pos == MAX_LINE_LENGTH
207                  || p_cmd[ i_cmd_pos ] == '\r'
208                  || p_cmd[ i_cmd_pos ] == '\n' )
209             {
210                 p_cmd[ i_cmd_pos ] = 0;
211                 b_complete = 1;
212             }
213         }
214
215         /* Is there something to do? */
216         if( b_complete == 1 )
217         {
218             switch( p_cmd[ 0 ] )
219             {
220             case 'a':
221             case 'A':
222                 if( p_cmd[ 1 ] == ' ' )
223                 {
224                     intf_PlaylistAdd( p_main->p_playlist,
225                                       PLAYLIST_END, p_cmd + 2 );
226                     if( p_intf->p_input != NULL )
227                     {
228                         p_intf->p_input->b_eof = 1;
229                     }
230                     intf_PlaylistJumpto( p_main->p_playlist,
231                                          p_main->p_playlist->i_size - 2 );
232                 }
233                 break;
234
235             case 'p':
236             case 'P':
237                 if( p_intf->p_input != NULL )
238                 {
239                     input_SetStatus( p_intf->p_input, INPUT_STATUS_PAUSE );
240                 }
241                 break;
242
243             case 'f':
244             case 'F':
245                 vlc_mutex_lock( &p_vout_bank->lock );
246                 /* XXX: only fullscreen the first video output */
247                 if( p_vout_bank->i_count )
248                 {
249                     p_vout_bank->pp_vout[0]->i_changes
250                                       |= VOUT_FULLSCREEN_CHANGE;
251                 }
252                 vlc_mutex_unlock( &p_vout_bank->lock );
253                 break;
254
255             case 'm':
256             case 'M':
257 #if 0
258                 double picratio = p_intf->p_input->p_default_vout->i_width 
259                     / p_intf->p_input->p_default_vout->i_height;
260                 if (picratio
261                 p_intf->p_input->p_default_vout->i_width=800
262                 p_intf->p_input->p_default_vout->i_changes |= 
263                     VOUT_FULLSCREEN_CHANGE;
264 #endif
265                 break;
266
267             case 's':
268             case 'S':
269                 ;
270                 break;
271
272             case 'q':
273             case 'Q':
274                 p_intf->b_die = 1;
275                 break;
276
277             case 'r':
278             case 'R':
279                 if( p_intf->p_input != NULL )
280                 {
281                     for( i_dummy = 1;
282                          i_dummy < MAX_LINE_LENGTH && p_cmd[ i_dummy ] >= '0'
283                                                    && p_cmd[ i_dummy ] <= '9';
284                          i_dummy++ )
285                     {
286                         ;
287                     }
288
289                     p_cmd[ i_dummy ] = 0;
290                     f_cpos = atof( p_cmd + 1 );
291                     input_Seek( p_intf->p_input, (off_t) (f_cpos / f_ratio) );
292                     /* rcreseek(f_cpos); */
293                 }
294                 break;
295
296             case '?':
297             case 'h':
298             case 'H':
299                 intf_Msg( "rc: help for remote control commands" );
300                 intf_Msg( "rc: h                                       help" );
301                 intf_Msg( "rc: a XYZ                 append XYZ to playlist" );
302                 intf_Msg( "rc: p                               toggle pause" );
303                 intf_Msg( "rc: f                          toggle fullscreen" );
304                 intf_Msg( "rc: r X    seek in seconds, for instance `r 3.5'" );
305                 intf_Msg( "rc: q                                       quit" );
306                 intf_Msg( "rc: end of help" );
307                 break;
308
309             default:
310                 intf_Msg( "rc: unknown command `%s'", p_cmd );
311                 break;
312             }
313         }
314
315         p_intf->pf_manage( p_intf );
316         msleep( INTF_IDLE_SLEEP );
317     }
318 }
319