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