]> git.sesse.net Git - vlc/blob - modules/control/rc.c
* src/input/control.c: added INPUT_ADD_INFO/INPUT_SET_NAME to input_Control().
[vlc] / modules / control / rc.c
1 /*****************************************************************************
2  * rc.c : remote control stdin/stdout module for vlc
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Author: 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/aout.h>
38 #include <vlc/vout.h>
39
40 #ifdef HAVE_UNISTD_H
41 #    include <unistd.h>
42 #endif
43
44 #ifdef HAVE_SYS_TIME_H
45 #    include <sys/time.h>
46 #endif
47 #include <sys/types.h>
48
49 #include "vlc_error.h"
50
51 #define MAX_LINE_LENGTH 256
52
53 /*****************************************************************************
54  * Local prototypes
55  *****************************************************************************/
56 static int  Activate     ( vlc_object_t * );
57 static void Run          ( intf_thread_t *p_intf );
58
59 static int  Input        ( vlc_object_t *, char const *,
60                            vlc_value_t, vlc_value_t, void * );
61 static int  Playlist     ( vlc_object_t *, char const *,
62                            vlc_value_t, vlc_value_t, void * );
63 static int  Quit         ( vlc_object_t *, char const *,
64                            vlc_value_t, vlc_value_t, void * );
65 static int  Intf         ( vlc_object_t *, char const *,
66                            vlc_value_t, vlc_value_t, void * );
67 static int  Volume       ( vlc_object_t *, char const *,
68                            vlc_value_t, vlc_value_t, void * );
69 static int  VolumeMove   ( vlc_object_t *, char const *,
70                            vlc_value_t, vlc_value_t, void * );
71 static int  AudioConfig  ( vlc_object_t *, char const *,
72                            vlc_value_t, vlc_value_t, void * );
73
74 /*****************************************************************************
75  * Module descriptor
76  *****************************************************************************/
77 #define POS_TEXT N_("Show stream position")
78 #define POS_LONGTEXT N_("Show the current position in seconds within the stream from time to time.")
79
80 #define TTY_TEXT N_("Fake TTY")
81 #define TTY_LONGTEXT N_("Force the rc module to use stdin as if it was a TTY.")
82
83 vlc_module_begin();
84     set_description( _("Remote control interface") );
85     add_bool( "rc-show-pos", 0, NULL, POS_TEXT, POS_LONGTEXT, VLC_TRUE );
86 #ifdef HAVE_ISATTY
87     add_bool( "fake-tty", 0, NULL, TTY_TEXT, TTY_LONGTEXT, VLC_TRUE );
88 #endif
89     set_capability( "interface", 20 );
90     set_callbacks( Activate, NULL );
91 vlc_module_end();
92
93 /*****************************************************************************
94  * Activate: initialize and create stuff
95  *****************************************************************************/
96 static int Activate( vlc_object_t *p_this )
97 {
98     intf_thread_t *p_intf = (intf_thread_t*)p_this;
99
100 #if defined(HAVE_ISATTY) && !defined(WIN32)
101     /* Check that stdin is a TTY */
102     if( !config_GetInt( p_intf, "fake-tty" ) && !isatty( 0 ) )
103     {
104         msg_Warn( p_intf, "fd 0 is not a TTY" );
105         return VLC_EGENERIC;
106     }
107 #endif
108
109     /* Non-buffered stdout */
110     setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
111
112     p_intf->pf_run = Run;
113
114     CONSOLE_INTRO_MSG;
115
116     printf( "Remote control interface initialized, `h' for help\n" );
117     return VLC_SUCCESS;
118 }
119
120 /*****************************************************************************
121  * Run: rc thread
122  *****************************************************************************
123  * This part of the interface is in a separate thread so that we can call
124  * exec() from within it without annoying the rest of the program.
125  *****************************************************************************/
126 static void Run( intf_thread_t *p_intf )
127 {
128     input_thread_t * p_input;
129     playlist_t *     p_playlist;
130
131     char       p_buffer[ MAX_LINE_LENGTH + 1 ];
132     vlc_bool_t b_showpos = config_GetInt( p_intf, "rc-show-pos" );
133
134     int        i_dummy;
135     off_t      i_oldpos = 0;
136     off_t      i_newpos;
137
138     double     f_ratio = 1.0;
139
140 #ifdef WIN32
141     HANDLE hConsoleIn;
142     INPUT_RECORD input_record;
143     DWORD i_dummy2;
144 #endif
145
146     p_input = NULL;
147     p_playlist = NULL;
148
149     /* Register commands that will be cleaned up upon object destruction */
150     var_Create( p_intf, "quit", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
151     var_AddCallback( p_intf, "quit", Quit, NULL );
152     var_Create( p_intf, "intf", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
153     var_AddCallback( p_intf, "intf", Intf, NULL );
154
155     var_Create( p_intf, "add", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
156     var_AddCallback( p_intf, "add", Playlist, NULL );
157     var_Create( p_intf, "playlist", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
158     var_AddCallback( p_intf, "playlist", Playlist, NULL );
159     var_Create( p_intf, "play", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
160     var_AddCallback( p_intf, "play", Playlist, NULL );
161     var_Create( p_intf, "stop", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
162     var_AddCallback( p_intf, "stop", Playlist, NULL );
163     var_Create( p_intf, "prev", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
164     var_AddCallback( p_intf, "prev", Playlist, NULL );
165     var_Create( p_intf, "next", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
166     var_AddCallback( p_intf, "next", Playlist, NULL );
167
168     var_Create( p_intf, "pause", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
169     var_AddCallback( p_intf, "pause", Input, NULL );
170     var_Create( p_intf, "seek", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
171     var_AddCallback( p_intf, "seek", Input, NULL );
172     var_Create( p_intf, "title", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
173     var_AddCallback( p_intf, "title", Input, NULL );
174     var_Create( p_intf, "title_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
175     var_AddCallback( p_intf, "title_n", Input, NULL );
176     var_Create( p_intf, "title_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
177     var_AddCallback( p_intf, "title_p", Input, NULL );
178     var_Create( p_intf, "chapter", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
179     var_AddCallback( p_intf, "chapter", Input, NULL );
180     var_Create( p_intf, "chapter_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
181     var_AddCallback( p_intf, "chapter_n", Input, NULL );
182     var_Create( p_intf, "chapter_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
183     var_AddCallback( p_intf, "chapter_p", Input, NULL );
184
185     var_Create( p_intf, "volume", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
186     var_AddCallback( p_intf, "volume", Volume, NULL );
187     var_Create( p_intf, "volup", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
188     var_AddCallback( p_intf, "volup", VolumeMove, NULL );
189     var_Create( p_intf, "voldown", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
190     var_AddCallback( p_intf, "voldown", VolumeMove, NULL );
191     var_Create( p_intf, "adev", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
192     var_AddCallback( p_intf, "adev", AudioConfig, NULL );
193     var_Create( p_intf, "achan", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
194     var_AddCallback( p_intf, "achan", AudioConfig, NULL );
195
196 #ifdef WIN32
197     /* Get the file descriptor of the console input */
198     hConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
199     if( hConsoleIn == INVALID_HANDLE_VALUE )
200     {
201         msg_Err( p_intf, "Couldn't open STD_INPUT_HANDLE" );
202         p_intf->b_die = VLC_TRUE;
203     }
204 #endif
205
206     while( !p_intf->b_die )
207     {
208         vlc_bool_t     b_complete = VLC_FALSE;
209
210 #ifndef WIN32
211         fd_set         fds;
212         struct timeval tv;
213
214         /* Check stdin */
215         tv.tv_sec = 0;
216         tv.tv_usec = (long)INTF_IDLE_SLEEP;
217         FD_ZERO( &fds );
218         FD_SET( STDIN_FILENO, &fds );
219
220         i_dummy = select( STDIN_FILENO + 1, &fds, NULL, NULL, &tv );
221 #else
222         /* On Win32, select() only works on socket descriptors */
223         i_dummy = ( WaitForSingleObject( hConsoleIn, INTF_IDLE_SLEEP/1000 )
224                     == WAIT_OBJECT_0 );
225 #endif
226         if( i_dummy > 0 )
227         {
228             int i_size = 0;
229
230             while( !p_intf->b_die
231                     && i_size < MAX_LINE_LENGTH
232 #ifndef WIN32
233                     && read( STDIN_FILENO, p_buffer + i_size, 1 ) > 0
234 #else
235                     && ReadConsoleInput( hConsoleIn, &input_record, 1,
236                                          &i_dummy2 )
237 #endif
238                    )
239             {
240 #ifdef WIN32
241                 if( input_record.EventType != KEY_EVENT ||
242                     !input_record.Event.KeyEvent.bKeyDown ||
243                     input_record.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT ||
244                     input_record.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL||
245                     input_record.Event.KeyEvent.wVirtualKeyCode == VK_MENU ||
246                     input_record.Event.KeyEvent.wVirtualKeyCode == VK_CAPITAL )
247                 {
248                     /* nothing interesting */
249                     continue;
250                 }
251
252                 p_buffer[ i_size ] =
253                     input_record.Event.KeyEvent.uChar.AsciiChar;
254
255                 /* Echo out the command */
256                 putc( p_buffer[ i_size ], stdout );
257
258                 /* Handle special keys */
259                 if( p_buffer[ i_size ] == '\r' || p_buffer[ i_size ] == '\n' )
260                 {
261                     putc( '\n', stdout );
262                     break;
263                 }
264                 switch( p_buffer[ i_size ] )
265                 {
266                 case '\b':
267                     if( i_size )
268                     {
269                         i_size -= 2;
270                         putc( ' ', stdout );
271                         putc( '\b', stdout );
272                     }
273                     break;
274                 case '\r':
275                     i_size --;
276                     break;
277                 }
278
279                 i_size++;
280 #else
281
282                 if( p_buffer[ i_size ] == '\r' || p_buffer[ i_size ] == '\n' )
283                 {
284                     break;
285                 }
286
287                 i_size++;
288 #endif
289             }
290
291             if( i_size == MAX_LINE_LENGTH
292                  || p_buffer[ i_size ] == '\r'
293                  || p_buffer[ i_size ] == '\n' )
294             {
295                 p_buffer[ i_size ] = 0;
296                 b_complete = VLC_TRUE;
297             }
298         }
299
300         /* Manage the input part */
301         if( p_input == NULL )
302         {
303             if( p_playlist )
304             {
305                 p_input = vlc_object_find( p_playlist, VLC_OBJECT_INPUT,
306                                                        FIND_CHILD );
307             }
308             else
309             {
310                 p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
311                                                    FIND_ANYWHERE );
312                 if( p_input )
313                 {
314                     p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
315                                                            FIND_PARENT );
316                 }
317             }
318         }
319         else if( p_input->b_dead )
320         {
321             vlc_object_release( p_input );
322             p_input = NULL;
323         }
324
325         if( p_input && b_showpos )
326         {
327             /* Get position */
328             vlc_mutex_lock( &p_input->stream.stream_lock );
329             if( !p_input->b_die && p_input->stream.i_mux_rate )
330             {
331 #define A p_input->stream.p_selected_area
332                 f_ratio = 1.0 / ( 50 * p_input->stream.i_mux_rate );
333                 i_newpos = A->i_tell * f_ratio;
334
335                 if( i_oldpos != i_newpos )
336                 {
337                     i_oldpos = i_newpos;
338                     printf( "pos: %li s / %li s\n", (long int)i_newpos,
339                             (long int)(f_ratio * A->i_size) );
340                 }
341 #undef S
342             }
343             vlc_mutex_unlock( &p_input->stream.stream_lock );
344         }
345
346         /* Is there something to do? */
347         if( b_complete )
348         {
349             char *psz_cmd, *psz_arg;
350
351             /* Skip heading spaces */
352             psz_cmd = p_buffer;
353             while( *psz_cmd == ' ' )
354             {
355                 psz_cmd++;
356             }
357
358             /* Split psz_cmd at the first space and make sure that
359              * psz_arg is valid */
360             psz_arg = strchr( psz_cmd, ' ' );
361             if( psz_arg )
362             {
363                 *psz_arg++ = 0;
364                 while( *psz_arg == ' ' )
365                 {
366                     psz_arg++;
367                 }
368             }
369             else
370             {
371                 psz_arg = "";
372             }
373
374             /* If the user typed a registered local command, try it */
375             if( var_Type( p_intf, psz_cmd ) & VLC_VAR_ISCOMMAND )
376             {
377                 vlc_value_t val;
378                 int i_ret;
379
380                 val.psz_string = psz_arg;
381                 i_ret = var_Set( p_intf, psz_cmd, val );
382                 printf( "%s: returned %i (%s)\n",
383                         psz_cmd, i_ret, vlc_error( i_ret ) );
384             }
385             /* Or maybe it's a global command */
386             else if( var_Type( p_intf->p_libvlc, psz_cmd ) & VLC_VAR_ISCOMMAND )
387             {
388                 vlc_value_t val;
389                 int i_ret;
390
391                 val.psz_string = psz_arg;
392                 /* FIXME: it's a global command, but we should pass the
393                  * local object as an argument, not p_intf->p_libvlc. */
394                 i_ret = var_Set( p_intf->p_libvlc, psz_cmd, val );
395                 printf( "%s: returned %i (%s)\n",
396                         psz_cmd, i_ret, vlc_error( i_ret ) );
397             }
398             else if( !strcmp( psz_cmd, "info" ) )
399             {
400                 if ( p_input )
401                 {
402                     int i, j;
403                     vlc_mutex_lock( &p_input->p_item->lock );
404                     for ( i = 0; i < p_input->p_item->i_categories; i++ )
405                     {
406                         info_category_t *p_category =
407                             p_input->p_item->pp_categories[i];
408
409                         printf( "+----[ %s ]\n", p_category->psz_name );
410                         printf( "| \n" );
411                         for ( j = 0; j < p_category->i_infos; j++ )
412                         {
413                             info_t *p_info = p_category->pp_infos[j];
414                             printf( "| %s: %s\n", p_info->psz_name,
415                                     p_info->psz_value );
416                         }
417                         printf( "| \n" );
418                     }
419                     printf( "+----[ end of stream info ]\n" );
420                     vlc_mutex_unlock( &p_input->p_item->lock );
421                 }
422                 else
423                 {
424                     printf( "no input\n" );
425                 }
426             }
427             else switch( psz_cmd[0] )
428             {
429             case 'f':
430             case 'F':
431                 if( p_input )
432                 {
433                     vout_thread_t *p_vout;
434                     p_vout = vlc_object_find( p_input,
435                                               VLC_OBJECT_VOUT, FIND_CHILD );
436
437                     if( p_vout )
438                     {
439                         p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
440                         vlc_object_release( p_vout );
441                     }
442                 }
443                 break;
444
445             case 's':
446             case 'S':
447                 ;
448                 break;
449
450             case '?':
451             case 'h':
452             case 'H':
453                 printf("+----[ Remote control commands ]\n");
454                 printf("| \n");
455                 printf("| add XYZ  . . . . . . . . . . add XYZ to playlist\n");
456                 printf("| playlist . . .  show items currently in playlist\n");
457                 printf("| play . . . . . . . . . . . . . . . . play stream\n");
458                 printf("| stop . . . . . . . . . . . . . . . . stop stream\n");
459                 printf("| next . . . . . . . . . . . .  next playlist item\n");
460                 printf("| prev . . . . . . . . . .  previous playlist item\n");
461                 printf("| title [X]  . . . . set/get title in current item\n");
462                 printf("| title_n  . . . . . .  next title in current item\n");
463                 printf("| title_p  . . . .  previous title in current item\n");
464                 printf("| chapter [X]  . . set/get chapter in current item\n");
465                 printf("| chapter_n  . . . .  next chapter in current item\n");
466                 printf("| chapter_p  . .  previous chapter in current item\n");
467                 printf("| \n");
468                 printf("| seek X . seek in seconds, for instance `seek 12'\n");
469                 printf("| pause  . . . . . . . . . . . . . .  toggle pause\n");
470                 printf("| f  . . . . . . . . . . . . . . toggle fullscreen\n");
471                 printf("| info . . .  information about the current stream\n");
472                 printf("| \n");
473                 printf("| volume [X] . . . . . . . .  set/get audio volume\n");
474                 printf("| volup [X]  . . . . .  raise audio volume X steps\n");
475                 printf("| voldown [X]  . . . .  lower audio volume X steps\n");
476                 printf("| adev [X] . . . . . . . . .  set/get audio device\n");
477                 printf("| achan [X]. . . . . . . .  set/get audio channels\n");
478                 printf("| \n");
479                 printf("| help . . . . . . . . . . . . . this help message\n");
480                 printf("| quit . . . . . . . . . . . . . . . . .  quit vlc\n");
481                 printf("| \n");
482                 printf("+----[ end of help ]\n");
483                 break;
484             case '\0':
485                 /* Ignore empty lines */
486                 break;
487             default:
488                 printf( "unknown command `%s', type `help' for help\n", psz_cmd );
489                 break;
490             }
491         }
492     }
493
494     if( p_input )
495     {
496         vlc_object_release( p_input );
497         p_input = NULL;
498     }
499
500     if( p_playlist )
501     {
502         vlc_object_release( p_playlist );
503         p_playlist = NULL;
504     }
505 }
506
507 static int Input( vlc_object_t *p_this, char const *psz_cmd,
508                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
509 {
510     input_thread_t * p_input;
511     vlc_value_t     val;
512
513     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
514
515     if( !p_input )
516     {
517         return VLC_ENOOBJ;
518     }
519
520     /* Parse commands that only require an input */
521     if( !strcmp( psz_cmd, "pause" ) )
522     {
523         val.i_int = PAUSE_S;
524
525         var_Set( p_input, "state", val );
526         vlc_object_release( p_input );
527         return VLC_SUCCESS;
528     }
529     else if( !strcmp( psz_cmd, "seek" ) )
530     {
531         if( strlen( newval.psz_string ) > 0 &&
532             newval.psz_string[strlen( newval.psz_string ) - 1] == '%' )
533         {
534             val.f_float = (float)atoi( newval.psz_string ) / 100.0;
535             var_Set( p_input, "position", val );
536         }
537         else
538         {
539             val.i_time = ((int64_t)atoi( newval.psz_string )) * 1000000;
540             var_Set( p_input, "time", val );
541         }
542         vlc_object_release( p_input );
543         return VLC_SUCCESS;
544     }
545     else if( !strcmp( psz_cmd, "chapter" ) ||
546              !strcmp( psz_cmd, "chapter_n" ) ||
547              !strcmp( psz_cmd, "chapter_p" ) )
548     {
549         if( !strcmp( psz_cmd, "chapter" ) )
550         {
551             if ( *newval.psz_string )
552             {
553                 /* Set. */
554                 val.i_int = atoi( newval.psz_string );
555                 var_Set( p_input, "chapter", val );
556             }
557             else
558             {
559                 vlc_value_t val_list;
560
561                 /* Get. */
562                 var_Get( p_input, "chapter", &val );
563                 var_Change( p_input, "chapter", VLC_VAR_GETCHOICES, &val_list, NULL );
564                 printf( "Currently playing chapter %d/%d\n", val.i_int, val_list.p_list->i_count );
565                 var_Change( p_this, "chapter", VLC_VAR_FREELIST, &val_list, NULL );
566             }
567         }
568         else if( !strcmp( psz_cmd, "chapter_n" ) )
569         {
570             val.b_bool = VLC_TRUE;
571             var_Set( p_input, "next-chapter", val );
572         }
573         else if( !strcmp( psz_cmd, "chapter_p" ) )
574         {
575             val.b_bool = VLC_TRUE;
576             var_Set( p_input, "prev-chapter", val );
577         }
578
579         vlc_object_release( p_input );
580         return VLC_SUCCESS;
581     }
582     else if( !strcmp( psz_cmd, "title" ) ||
583              !strcmp( psz_cmd, "title_n" ) ||
584              !strcmp( psz_cmd, "title_p" ) )
585     {
586         if( !strcmp( psz_cmd, "title" ) )
587         {
588             if ( *newval.psz_string )
589             {
590                 /* Set. */
591                 val.i_int = atoi( newval.psz_string );
592                 var_Set( p_input, "title", val );
593             }
594             else
595             {
596                 vlc_value_t val_list;
597
598                 /* Get. */
599                 var_Get( p_input, "title", &val );
600                 var_Change( p_input, "title", VLC_VAR_GETCHOICES, &val_list, NULL );
601                 printf( "Currently playing title %d/%d\n", val.i_int, val_list.p_list->i_count );
602                 var_Change( p_this, "title", VLC_VAR_FREELIST, &val_list, NULL );
603             }
604         }
605         else if( !strcmp( psz_cmd, "title_n" ) )
606         {
607             val.b_bool = VLC_TRUE;
608             var_Set( p_input, "next-title", val );
609         }
610         else if( !strcmp( psz_cmd, "title_p" ) )
611         {
612             val.b_bool = VLC_TRUE;
613             var_Set( p_input, "prev-title", val );
614         }
615
616         vlc_object_release( p_input );
617         return VLC_SUCCESS;
618     }
619
620     /* Never reached. */
621     return VLC_EGENERIC;
622 }
623
624 static int Playlist( vlc_object_t *p_this, char const *psz_cmd,
625                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
626 {
627     playlist_t *     p_playlist;
628
629     p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
630                                            FIND_ANYWHERE );
631     if( !p_playlist )
632     {
633         return VLC_ENOOBJ;
634     }
635
636     /* Parse commands that require a playlist */
637     if( !strcmp( psz_cmd, "prev" ) )
638     {
639         playlist_Prev( p_playlist );
640     }
641     else if( !strcmp( psz_cmd, "next" ) )
642     {
643         playlist_Next( p_playlist );
644     }
645     else if( !strcmp( psz_cmd, "play" ) )
646     {
647         playlist_Play( p_playlist );
648     }
649     else if( !strcmp( psz_cmd, "stop" ) )
650     {
651         playlist_Stop( p_playlist );
652     }
653     else if( !strcmp( psz_cmd, "add" ) )
654     {
655         printf( "trying to add %s to playlist\n", newval.psz_string );
656         playlist_Add( p_playlist, newval.psz_string, newval.psz_string,
657                       PLAYLIST_GO|PLAYLIST_APPEND, PLAYLIST_END );
658     }
659     else if( !strcmp( psz_cmd, "playlist" ) )
660     {
661         int i;
662         for ( i = 0; i < p_playlist->i_size; i++ )
663         {
664             printf( "|%s%s   %s|\n", i == p_playlist->i_index?"*":" ",
665                     p_playlist->pp_items[i]->input.psz_name,
666                     p_playlist->pp_items[i]->input.psz_uri );
667         }
668         if ( i == 0 )
669         {
670             printf( "| no entries\n" );
671         }
672     }
673     /*
674      * sanity check
675      */
676     else
677     {
678         printf( "unknown command!\n" );
679     }
680
681     vlc_object_release( p_playlist );
682     return VLC_SUCCESS;
683 }
684
685 static int Quit( vlc_object_t *p_this, char const *psz_cmd,
686                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
687 {
688     p_this->p_vlc->b_die = VLC_TRUE;
689     return VLC_SUCCESS;
690 }
691
692 static int Intf( vlc_object_t *p_this, char const *psz_cmd,
693                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
694 {
695     intf_thread_t *p_newintf;
696
697     p_newintf = intf_Create( p_this->p_vlc, newval.psz_string );
698
699     if( p_newintf )
700     {
701         p_newintf->b_block = VLC_FALSE;
702         if( intf_RunThread( p_newintf ) )
703         {
704             vlc_object_detach( p_newintf );
705             intf_Destroy( p_newintf );
706         }
707     }
708
709     return VLC_SUCCESS;
710 }
711
712 static int Volume( vlc_object_t *p_this, char const *psz_cmd,
713                    vlc_value_t oldval, vlc_value_t newval, void *p_data )
714 {
715     int i_error;
716
717     if ( *newval.psz_string )
718     {
719         /* Set. */
720         audio_volume_t i_volume = atoi( newval.psz_string );
721         if ( i_volume > AOUT_VOLUME_MAX )
722         {
723             printf( "Volume must be in the range %d-%d\n", AOUT_VOLUME_MIN,
724                     AOUT_VOLUME_MAX );
725             i_error = VLC_EBADVAR;
726         }
727         else i_error = aout_VolumeSet( p_this, i_volume );
728     }
729     else
730     {
731         /* Get. */
732         audio_volume_t i_volume;
733         if ( aout_VolumeGet( p_this, &i_volume ) < 0 )
734         {
735             i_error = VLC_EGENERIC;
736         }
737         else
738         {
739             printf( "Volume is %d\n", i_volume );
740             i_error = VLC_SUCCESS;
741         }
742     }
743
744     return i_error;
745 }
746
747 static int VolumeMove( vlc_object_t *p_this, char const *psz_cmd,
748                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
749 {
750     audio_volume_t i_volume;
751     int i_nb_steps = atoi(newval.psz_string);
752     int i_error = VLC_SUCCESS;
753
754     if ( i_nb_steps <= 0 || i_nb_steps > (AOUT_VOLUME_MAX/AOUT_VOLUME_STEP) )
755     {
756         i_nb_steps = 1;
757     }
758
759     if ( !strcmp(psz_cmd, "volup") )
760     {
761         if ( aout_VolumeUp( p_this, i_nb_steps, &i_volume ) < 0 )
762             i_error = VLC_EGENERIC;
763     }
764     else
765     {
766         if ( aout_VolumeDown( p_this, i_nb_steps, &i_volume ) < 0 )
767             i_error = VLC_EGENERIC;
768     }
769
770     if ( !i_error ) printf( "Volume is %d\n", i_volume );
771     return i_error;
772 }
773
774 static int AudioConfig( vlc_object_t *p_this, char const *psz_cmd,
775                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
776 {
777     aout_instance_t * p_aout;
778     const char * psz_variable;
779     vlc_value_t val_name;
780     int i_error;
781
782     p_aout = vlc_object_find( p_this, VLC_OBJECT_AOUT, FIND_ANYWHERE );
783     if ( p_aout == NULL ) return VLC_ENOOBJ;
784
785     if ( !strcmp( psz_cmd, "adev" ) )
786     {
787         psz_variable = "audio-device";
788     }
789     else
790     {
791         psz_variable = "audio-channels";
792     }
793
794     /* Get the descriptive name of the variable */
795     var_Change( (vlc_object_t *)p_aout, psz_variable, VLC_VAR_GETTEXT,
796                  &val_name, NULL );
797     if( !val_name.psz_string ) val_name.psz_string = strdup(psz_variable);
798
799     if ( !*newval.psz_string )
800     {
801         /* Retrieve all registered ***. */
802         vlc_value_t val, text;
803         int i, i_value;
804
805         if ( var_Get( (vlc_object_t *)p_aout, psz_variable, &val ) < 0 )
806         {
807             vlc_object_release( (vlc_object_t *)p_aout );
808             return VLC_EGENERIC;
809         }
810         i_value = val.i_int;
811
812         if ( var_Change( (vlc_object_t *)p_aout, psz_variable,
813                          VLC_VAR_GETLIST, &val, &text ) < 0 )
814         {
815             vlc_object_release( (vlc_object_t *)p_aout );
816             return VLC_EGENERIC;
817         }
818
819         printf( "+----[ %s ]\n", val_name.psz_string );
820         for ( i = 0; i < val.p_list->i_count; i++ )
821         {
822             if ( i_value == val.p_list->p_values[i].i_int )
823                 printf( "| %i - %s *\n", val.p_list->p_values[i].i_int,
824                         text.p_list->p_values[i].psz_string );
825             else
826                 printf( "| %i - %s\n", val.p_list->p_values[i].i_int,
827                         text.p_list->p_values[i].psz_string );
828         }
829         var_Change( (vlc_object_t *)p_aout, psz_variable, VLC_VAR_FREELIST,
830                     &val, &text );
831         printf( "+----[ end of %s ]\n", val_name.psz_string );
832
833         if( val_name.psz_string ) free( val_name.psz_string );
834         i_error = VLC_SUCCESS;
835     }
836     else
837     {
838         vlc_value_t val;
839         val.i_int = atoi( newval.psz_string );
840
841         i_error = var_Set( (vlc_object_t *)p_aout, psz_variable, val );
842     }
843     vlc_object_release( (vlc_object_t *)p_aout );
844
845     return i_error;
846 }