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