rc.c 36 KB
Newer Older
1
/*****************************************************************************
Anil Daoud's avatar
Anil Daoud committed
2
 * rc.c : remote control stdin/stdout module for vlc
3
 *****************************************************************************
Anil Daoud's avatar
Anil Daoud committed
4
 * Copyright (C) 2004 VideoLAN
5
 * $Id$
6
 *
7
 * Author: Peter Surda <shurdeek@panorama.sth.ac.at>
8 9 10 11 12
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
13
 *
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */
#include <string.h>

#include <errno.h>                                                 /* ENOMEM */
#include <stdio.h>
#include <ctype.h>
33
#include <signal.h>
34 35 36

#include <vlc/vlc.h>
#include <vlc/intf.h>
37
#include <vlc/aout.h>
38 39 40 41 42 43 44 45 46 47 48
#include <vlc/vout.h>

#ifdef HAVE_UNISTD_H
#    include <unistd.h>
#endif

#ifdef HAVE_SYS_TIME_H
#    include <sys/time.h>
#endif
#include <sys/types.h>

49
#include "vlc_error.h"
50 51
#include "network.h"

52 53 54 55 56 57 58 59
#if defined(PF_UNIX) && !defined(PF_LOCAL)
#    define PF_LOCAL PF_UNIX
#endif
#if defined(AF_UNIX) && !defined(AF_LOCAL)
#    define AF_LOCAL AF_UNIX
#endif

#ifdef PF_LOCAL
60 61
#    include <sys/un.h>
#endif
62

63 64 65 66 67 68
#define MAX_LINE_LENGTH 256

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int  Activate     ( vlc_object_t * );
69 70 71 72
static void Deactivate   ( vlc_object_t * );
static void Run          ( intf_thread_t * );

static vlc_bool_t ReadCommand( intf_thread_t *, char *, int * );
73

74 75
static int  Input        ( vlc_object_t *, char const *,
                           vlc_value_t, vlc_value_t, void * );
gbazin's avatar
 
gbazin committed
76 77 78 79 80 81 82 83 84 85 86 87
static int  Playlist     ( vlc_object_t *, char const *,
                           vlc_value_t, vlc_value_t, void * );
static int  Quit         ( vlc_object_t *, char const *,
                           vlc_value_t, vlc_value_t, void * );
static int  Intf         ( vlc_object_t *, char const *,
                           vlc_value_t, vlc_value_t, void * );
static int  Volume       ( vlc_object_t *, char const *,
                           vlc_value_t, vlc_value_t, void * );
static int  VolumeMove   ( vlc_object_t *, char const *,
                           vlc_value_t, vlc_value_t, void * );
static int  AudioConfig  ( vlc_object_t *, char const *,
                           vlc_value_t, vlc_value_t, void * );
88

89 90 91 92
struct intf_sys_t
{
    int i_socket_listen;
    int i_socket;
93
    char *psz_unix_path;
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113

#ifdef WIN32
    HANDLE hConsoleIn;
#endif
};

#ifdef HAVE_VARIADIC_MACROS
#   define printf( psz_format, args... ) \
      Printf( p_intf, psz_format, ## args )
#endif

void Printf( intf_thread_t *p_intf, const char *psz_fmt, ... )
{
    va_list args;
    va_start( args, psz_fmt );
    if( p_intf->p_sys->i_socket == -1 ) vprintf( psz_fmt, args );
    else net_vaPrintf( p_intf, p_intf->p_sys->i_socket, psz_fmt, args );
    va_end( args );
}

114 115 116
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
Christophe Massiot's avatar
Christophe Massiot committed
117
#define POS_TEXT N_("Show stream position")
118 119
#define POS_LONGTEXT N_("Show the current position in seconds within the " \
                        "stream from time to time." )
120

Christophe Massiot's avatar
Christophe Massiot committed
121
#define TTY_TEXT N_("Fake TTY")
Anil Daoud's avatar
Anil Daoud committed
122
#define TTY_LONGTEXT N_("Force the rc module to use stdin as if it was a TTY.")
123

124
#define UNIX_TEXT N_("UNIX socket command input")
125 126
#define UNIX_LONGTEXT N_("Accept commands over a Unix socket rather than " \
                         "stdin." )
127

128
#define HOST_TEXT N_("TCP command input")
129
#define HOST_LONGTEXT N_("Accept commands over a socket rather than stdin. " \
130 131
            "You can set the address and port the interface will bind to." )

132
vlc_module_begin();
gbazin's avatar
 
gbazin committed
133
    set_description( _("Remote control interface") );
134
    add_bool( "rc-show-pos", 0, NULL, POS_TEXT, POS_LONGTEXT, VLC_TRUE );
Sam Hocevar's avatar
Sam Hocevar committed
135
#ifdef HAVE_ISATTY
136
    add_bool( "rc-fake-tty", 0, NULL, TTY_TEXT, TTY_LONGTEXT, VLC_TRUE );
Sam Hocevar's avatar
Sam Hocevar committed
137
#endif
138
    add_string( "rc-unix", 0, NULL, UNIX_TEXT, UNIX_LONGTEXT, VLC_TRUE );
139
    add_string( "rc-host", 0, NULL, HOST_TEXT, HOST_LONGTEXT, VLC_TRUE );
140
    set_capability( "interface", 20 );
141
    set_callbacks( Activate, Deactivate );
142 143 144 145 146 147 148 149
vlc_module_end();

/*****************************************************************************
 * Activate: initialize and create stuff
 *****************************************************************************/
static int Activate( vlc_object_t *p_this )
{
    intf_thread_t *p_intf = (intf_thread_t*)p_this;
150
    char *psz_host, *psz_unix_path;
151
    int i_socket = -1;
152

gbazin's avatar
 
gbazin committed
153
#if defined(HAVE_ISATTY) && !defined(WIN32)
154
    /* Check that stdin is a TTY */
155
    if( !config_GetInt( p_intf, "rc-fake-tty" ) && !isatty( 0 ) )
156 157
    {
        msg_Warn( p_intf, "fd 0 is not a TTY" );
158
        return VLC_EGENERIC;
159 160 161
    }
#endif

162 163
    psz_unix_path = config_GetPsz( p_intf, "rc-unix" );
    if( psz_unix_path )
164
    {
165
#ifndef PF_LOCAL
166
        msg_Warn( p_intf, "your OS doesn't support filesystem sockets" );
167
        free( psz_unix_path );
168 169 170 171 172 173 174 175 176
        return VLC_EGENERIC;
#else
        struct sockaddr_un addr;
        int i_ret;

        memset( &addr, 0, sizeof(struct sockaddr_un) );

        msg_Dbg( p_intf, "trying UNIX socket" );

177
        if( (i_socket = socket( PF_LOCAL, SOCK_STREAM, 0 ) ) < 0 )
178 179
        {
            msg_Warn( p_intf, "can't open socket: %s", strerror(errno) );
180
            free( psz_unix_path );
181 182 183
            return VLC_EGENERIC;
        }

184 185 186
        addr.sun_family = AF_LOCAL;
        strncpy( addr.sun_path, psz_unix_path, sizeof( addr.sun_path ) );
        addr.sun_path[sizeof( addr.sun_path ) - 1] = '\0';
187 188 189 190 191 192

        if( (i_ret = bind( i_socket, (struct sockaddr*)&addr,
                           sizeof(struct sockaddr_un) ) ) < 0 )
        {
            msg_Warn( p_intf, "couldn't bind socket to address: %s",
                      strerror(errno) );
193 194
            free( psz_unix_path );
            net_Close( i_socket );
195 196 197 198 199 200
            return VLC_EGENERIC;
        }

        if( ( i_ret = listen( i_socket, 1 ) ) < 0 )
        {
            msg_Warn( p_intf, "can't listen on socket: %s", strerror(errno));
201 202
            free( psz_unix_path );
            net_Close( i_socket );
203 204 205 206
            return VLC_EGENERIC;
        }
#endif
    }
207 208 209

    if( ( i_socket == -1) &&
        ( psz_host = config_GetPsz( p_intf, "rc-host" ) ) != NULL )
210 211 212
    {
        vlc_url_t url;

213 214 215 216 217
        vlc_UrlParse( &url, psz_host, 0 );

        msg_Dbg( p_intf, "base %s port %d", url.psz_host, url.i_port );

        if( (i_socket = net_ListenTCP(p_this, url.psz_host, url.i_port)) == -1)
218
        {
219 220
            msg_Warn( p_intf, "can't listen to %s port %i",
                      url.psz_host, url.i_port );
221 222 223 224 225 226
            vlc_UrlClean( &url );
            free( psz_host );
            return VLC_EGENERIC;
        }

        vlc_UrlClean( &url );
227
        free( psz_host );
228 229 230 231 232 233 234 235 236 237 238
    }

    p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
    if( !p_intf->p_sys )
    {
        msg_Err( p_intf, "no memory" );
        return VLC_ENOMEM;
    }

    p_intf->p_sys->i_socket_listen = i_socket;
    p_intf->p_sys->i_socket = -1;
239
    p_intf->p_sys->psz_unix_path = psz_unix_path;
240

241 242 243 244 245
    /* Non-buffered stdout */
    setvbuf( stdout, (char *)NULL, _IOLBF, 0 );

    p_intf->pf_run = Run;

gbazin's avatar
 
gbazin committed
246
    CONSOLE_INTRO_MSG;
247

248
    printf( _("Remote control interface initialized, `h' for help\n") );
249
    return VLC_SUCCESS;
250 251
}

252 253 254 255 256 257 258 259 260 261 262
/*****************************************************************************
 * Deactivate: uninitialize and cleanup
 *****************************************************************************/
static void Deactivate( vlc_object_t *p_this )
{
    intf_thread_t *p_intf = (intf_thread_t*)p_this;

    if( p_intf->p_sys->i_socket_listen != -1 )
        net_Close( p_intf->p_sys->i_socket_listen );
    if( p_intf->p_sys->i_socket != -1 )
        net_Close( p_intf->p_sys->i_socket );
263 264 265 266 267 268 269
    if( p_intf->p_sys->psz_unix_path != NULL )
    {
#ifdef PF_LOCAL
        unlink( p_intf->p_sys->psz_unix_path );
#endif
        free( p_intf->p_sys->psz_unix_path );
    }
270 271 272
    free( p_intf->p_sys );
}

273 274 275 276 277 278 279 280 281
/*****************************************************************************
 * Run: rc thread
 *****************************************************************************
 * This part of the interface is in a separate thread so that we can call
 * exec() from within it without annoying the rest of the program.
 *****************************************************************************/
static void Run( intf_thread_t *p_intf )
{
    input_thread_t * p_input;
282
    playlist_t *     p_playlist;
283 284

    char       p_buffer[ MAX_LINE_LENGTH + 1 ];
285
    vlc_bool_t b_showpos = config_GetInt( p_intf, "rc-show-pos" );
286

287
    int        i_size = 0;
Laurent Aimar's avatar
Laurent Aimar committed
288 289
    int        i_oldpos = 0;
    int        i_newpos;
290

291
    p_buffer[0] = 0;
gbazin's avatar
 
gbazin committed
292 293 294
    p_input = NULL;
    p_playlist = NULL;

295
    /* Register commands that will be cleaned up upon object destruction */
gbazin's avatar
 
gbazin committed
296 297 298 299 300
    var_Create( p_intf, "quit", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "quit", Quit, NULL );
    var_Create( p_intf, "intf", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "intf", Intf, NULL );

301 302 303 304
    var_Create( p_intf, "add", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "add", Playlist, NULL );
    var_Create( p_intf, "playlist", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "playlist", Playlist, NULL );
gbazin's avatar
 
gbazin committed
305 306 307 308 309 310 311 312
    var_Create( p_intf, "play", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "play", Playlist, NULL );
    var_Create( p_intf, "stop", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "stop", Playlist, NULL );
    var_Create( p_intf, "prev", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "prev", Playlist, NULL );
    var_Create( p_intf, "next", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "next", Playlist, NULL );
313 314 315 316 317 318 319
  
    var_Create( p_intf, "marquee", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "marquee", Input, NULL );
    var_Create( p_intf, "marq-x", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "marq-x", Input, NULL );
    var_Create( p_intf, "marq-y", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "marq-y", Input, NULL );
gbazin's avatar
 
gbazin committed
320

321 322 323 324
    var_Create( p_intf, "pause", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "pause", Input, NULL );
    var_Create( p_intf, "seek", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "seek", Input, NULL );
gbazin's avatar
 
gbazin committed
325
    var_Create( p_intf, "title", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
326
    var_AddCallback( p_intf, "title", Input, NULL );
gbazin's avatar
 
gbazin committed
327
    var_Create( p_intf, "title_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
328
    var_AddCallback( p_intf, "title_n", Input, NULL );
gbazin's avatar
 
gbazin committed
329
    var_Create( p_intf, "title_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
330
    var_AddCallback( p_intf, "title_p", Input, NULL );
gbazin's avatar
 
gbazin committed
331
    var_Create( p_intf, "chapter", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
332
    var_AddCallback( p_intf, "chapter", Input, NULL );
gbazin's avatar
 
gbazin committed
333
    var_Create( p_intf, "chapter_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
334
    var_AddCallback( p_intf, "chapter_n", Input, NULL );
gbazin's avatar
 
gbazin committed
335
    var_Create( p_intf, "chapter_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
336
    var_AddCallback( p_intf, "chapter_p", Input, NULL );
gbazin's avatar
 
gbazin committed
337 338 339 340 341 342 343 344 345 346 347

    var_Create( p_intf, "volume", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "volume", Volume, NULL );
    var_Create( p_intf, "volup", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "volup", VolumeMove, NULL );
    var_Create( p_intf, "voldown", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "voldown", VolumeMove, NULL );
    var_Create( p_intf, "adev", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "adev", AudioConfig, NULL );
    var_Create( p_intf, "achan", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "achan", AudioConfig, NULL );
348

gbazin's avatar
 
gbazin committed
349 350
#ifdef WIN32
    /* Get the file descriptor of the console input */
351 352
    p_intf->p_sys->hConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
    if( p_intf->p_sys->hConsoleIn == INVALID_HANDLE_VALUE )
gbazin's avatar
 
gbazin committed
353
    {
354
        msg_Err( p_intf, "Couldn't open STD_INPUT_HANDLE" );
gbazin's avatar
 
gbazin committed
355
        p_intf->b_die = VLC_TRUE;
gbazin's avatar
 
gbazin committed
356 357 358
    }
#endif

359 360
    while( !p_intf->b_die )
    {
361 362
        char *psz_cmd, *psz_arg;
        vlc_bool_t b_complete;
363

364 365
        if( p_intf->p_sys->i_socket_listen != - 1 &&
            p_intf->p_sys->i_socket == -1 )
366
        {
367 368
            p_intf->p_sys->i_socket =
                net_Accept( p_intf, p_intf->p_sys->i_socket_listen, 0 );
369 370
        }

371 372
        b_complete = ReadCommand( p_intf, p_buffer, &i_size );

373 374 375
        /* Manage the input part */
        if( p_input == NULL )
        {
376 377 378 379 380 381 382 383 384
            if( p_playlist )
            {
                p_input = vlc_object_find( p_playlist, VLC_OBJECT_INPUT,
                                                       FIND_CHILD );
            }
            else
            {
                p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                                   FIND_ANYWHERE );
385
                if( p_input )
386 387 388 389 390
                {
                    p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
                                                           FIND_PARENT );
                }
            }
391 392 393 394 395 396 397
        }
        else if( p_input->b_dead )
        {
            vlc_object_release( p_input );
            p_input = NULL;
        }

398
        if( p_input && b_showpos )
399
        {
Laurent Aimar's avatar
Laurent Aimar committed
400 401
            i_newpos = 100 * var_GetFloat( p_input, "position" );
            if( i_oldpos != i_newpos )
402
            {
Laurent Aimar's avatar
Laurent Aimar committed
403 404
                i_oldpos = i_newpos;
                printf( "pos: %d%%\n", i_newpos );
405 406 407 408
            }
        }

        /* Is there something to do? */
409 410 411 412 413 414
        if( !b_complete ) continue;


        /* Skip heading spaces */
        psz_cmd = p_buffer;
        while( *psz_cmd == ' ' )
415
        {
416 417
            psz_cmd++;
        }
418

419 420 421 422 423 424 425
        /* Split psz_cmd at the first space and make sure that
         * psz_arg is valid */
        psz_arg = strchr( psz_cmd, ' ' );
        if( psz_arg )
        {
            *psz_arg++ = 0;
            while( *psz_arg == ' ' )
426
            {
427
                psz_arg++;
428
            }
429 430 431 432 433 434 435 436 437 438 439
        }
        else
        {
            psz_arg = "";
        }

        /* If the user typed a registered local command, try it */
        if( var_Type( p_intf, psz_cmd ) & VLC_VAR_ISCOMMAND )
        {
            vlc_value_t val;
            int i_ret;
440

441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
            val.psz_string = psz_arg;
            i_ret = var_Set( p_intf, psz_cmd, val );
            printf( _("%s: returned %i (%s)\n"),
                    psz_cmd, i_ret, vlc_error( i_ret ) );
        }
        /* Or maybe it's a global command */
        else if( var_Type( p_intf->p_libvlc, psz_cmd ) & VLC_VAR_ISCOMMAND )
        {
            vlc_value_t val;
            int i_ret;

            val.psz_string = psz_arg;
            /* FIXME: it's a global command, but we should pass the
             * local object as an argument, not p_intf->p_libvlc. */
            i_ret = var_Set( p_intf->p_libvlc, psz_cmd, val );
456 457 458 459 460
            if( i_ret != 0 )
            {
                printf( _("%s: returned %i (%s)\n"),
                         psz_cmd, i_ret, vlc_error( i_ret ) );
            }
461 462 463 464
        }
        else if( !strcmp( psz_cmd, "info" ) )
        {
            if( p_input )
465
            {
466 467 468
                int i, j;
                vlc_mutex_lock( &p_input->input.p_item->lock );
                for ( i = 0; i < p_input->input.p_item->i_categories; i++ )
469
                {
470 471 472 473 474 475 476 477 478 479 480 481
                    info_category_t *p_category =
                        p_input->input.p_item->pp_categories[i];

                    printf( "+----[ %s ]\n", p_category->psz_name );
                    printf( "| \n" );
                    for ( j = 0; j < p_category->i_infos; j++ )
                    {
                        info_t *p_info = p_category->pp_infos[j];
                        printf( "| %s: %s\n", p_info->psz_name,
                                p_info->psz_value );
                    }
                    printf( "| \n" );
482
                }
483 484
                printf( _("+----[ end of stream info ]\n") );
                vlc_mutex_unlock( &p_input->input.p_item->lock );
485
            }
486
            else
487
            {
488
                printf( _("no input\n") );
Sam Hocevar's avatar
Sam Hocevar committed
489
            }
490
        }
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
        else if( !strcmp( psz_cmd, "is_playing" ) )
        {
            if( ! p_input )
            {
                printf( "0\n" );
            }
            else
            {
                printf( "1\n" );
            }
        }
        else if( !strcmp( psz_cmd, "get_time" ) )
        {
            if( ! p_input )
            {
                printf("0\n");
            }
            else
            {
                vlc_value_t time;
                var_Get( p_input, "time", &time );
                printf( "%i\n", time.i_time / 1000000);
            }
        }
        else if( !strcmp( psz_cmd, "get_length" ) )
        {
            if( ! p_input )
            {
                printf("0\n");
            }
            else
            {
                vlc_value_t time;
                var_Get( p_input, "length", &time );
                printf( "%i\n", time.i_time / 1000000);
            }
        }
        else if( !strcmp( psz_cmd, "get_title" ) )
        {
            if( ! p_input )
            {
                printf("\n");
            }
            else
            {
                printf( "%s\n", p_input->input.p_item->psz_name );
            }
        }
539 540 541 542 543
        else switch( psz_cmd[0] )
        {
        case 'f':
        case 'F':
            if( p_input )
Sam Hocevar's avatar
Sam Hocevar committed
544
            {
545 546 547
                vout_thread_t *p_vout;
                p_vout = vlc_object_find( p_input,
                                          VLC_OBJECT_VOUT, FIND_CHILD );
548

549
                if( p_vout )
550
                {
551 552
                    p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
                    vlc_object_release( p_vout );
553 554
                }
            }
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
            break;

        case 's':
        case 'S':
            ;
            break;

        case '?':
        case 'h':
        case 'H':
            printf(_("+----[ Remote control commands ]\n"));
            printf("| \n");
            printf(_("| add XYZ  . . . . . . . . . . add XYZ to playlist\n"));
            printf(_("| playlist . . .  show items currently in playlist\n"));
            printf(_("| play . . . . . . . . . . . . . . . . play stream\n"));
            printf(_("| stop . . . . . . . . . . . . . . . . stop stream\n"));
            printf(_("| next . . . . . . . . . . . .  next playlist item\n"));
            printf(_("| prev . . . . . . . . . .  previous playlist item\n"));
            printf(_("| title [X]  . . . . set/get title in current item\n"));
            printf(_("| title_n  . . . . . .  next title in current item\n"));
            printf(_("| title_p  . . . .  previous title in current item\n"));
            printf(_("| chapter [X]  . . set/get chapter in current item\n"));
            printf(_("| chapter_n  . . . .  next chapter in current item\n"));
            printf(_("| chapter_p  . .  previous chapter in current item\n"));
            printf("| \n");
580 581 582 583
            printf(_("| marquee STRING . . . . . overlay STRING in video\n"));
            printf(_("| marq-x X . . . . . .offset of marquee, from left\n"));
            printf(_("| marq-y Y . . . . . . offset of marquee, from top\n"));
            printf("| \n");
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
            printf(_("| seek X . seek in seconds, for instance `seek 12'\n"));
            printf(_("| pause  . . . . . . . . . . . . . .  toggle pause\n"));
            printf(_("| f  . . . . . . . . . . . . . . toggle fullscreen\n"));
            printf(_("| info . . .  information about the current stream\n"));
            printf("| \n");
            printf(_("| volume [X] . . . . . . . .  set/get audio volume\n"));
            printf(_("| volup [X]  . . . . .  raise audio volume X steps\n"));
            printf(_("| voldown [X]  . . . .  lower audio volume X steps\n"));
            printf(_("| adev [X] . . . . . . . . .  set/get audio device\n"));
            printf(_("| achan [X]. . . . . . . .  set/get audio channels\n"));
            printf("| \n");
            printf(_("| help . . . . . . . . . . . . . this help message\n"));
            printf(_("| quit . . . . . . . . . . . . . . . . .  quit vlc\n"));
            printf("| \n");
            printf(_("+----[ end of help ]\n"));
            break;

        case '\0':
            /* Ignore empty lines */
            break;

        default:
            printf(_("unknown command `%s', type `help' for help\n"), psz_cmd);
            break;
608
        }
609 610 611

        /* Command processed */
        i_size = 0; p_buffer[0] = 0;
612 613 614 615 616 617
    }

    if( p_input )
    {
        vlc_object_release( p_input );
        p_input = NULL;
618
    }
619

620 621 622 623
    if( p_playlist )
    {
        vlc_object_release( p_playlist );
        p_playlist = NULL;
624
    }
625 626
}

627 628
static int Input( vlc_object_t *p_this, char const *psz_cmd,
                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
629
{
630 631
    intf_thread_t *p_intf = (intf_thread_t*)p_this;
    input_thread_t *p_input;
632
    vlc_value_t     val;
633 634

    p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
635
    if( !p_input ) return VLC_ENOOBJ;
636 637 638 639

    /* Parse commands that only require an input */
    if( !strcmp( psz_cmd, "pause" ) )
    {
640 641 642
        val.i_int = PAUSE_S;

        var_Set( p_input, "state", val );
643 644 645
        vlc_object_release( p_input );
        return VLC_SUCCESS;
    }
646 647
    else if( !strcmp( psz_cmd, "seek" ) )
    {
648 649 650
        if( strlen( newval.psz_string ) > 0 &&
            newval.psz_string[strlen( newval.psz_string ) - 1] == '%' )
        {
651 652
            val.f_float = (float)atoi( newval.psz_string ) / 100.0;
            var_Set( p_input, "position", val );
653 654 655
        }
        else
        {
gbazin's avatar
gbazin committed
656
            val.i_time = ((int64_t)atoi( newval.psz_string )) * 1000000;
657
            var_Set( p_input, "time", val );
658 659 660
        }
        vlc_object_release( p_input );
        return VLC_SUCCESS;
661
    }
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
    else if( !strcmp( psz_cmd, "marquee" ) )
    {
        if( strlen( newval.psz_string ) > 0 )
        {
            val.psz_string = newval.psz_string;
            /* check for the playlist structure */
            vlc_object_t *p_pl =
                  vlc_object_find( p_this, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
            if( !p_pl )
                {
                  return VLC_ENOOBJ;
                }
            var_Set( p_pl, "marquee", val );
            vlc_object_release( p_pl );
        }
        vlc_object_release( p_input );
        return VLC_SUCCESS;
    }
    else if( !strcmp( psz_cmd, "marq-x" ) )
    {
        if( strlen( newval.psz_string ) > 0) 
        {
            vlc_object_t *p_pl =
                  vlc_object_find( p_this, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
            if( !p_pl )
                {
                  return VLC_ENOOBJ;
                }
            val.i_int = atoi( newval.psz_string );
            var_Set( p_pl, "marq-x", val );
             vlc_object_release( p_pl );
        }
        vlc_object_release( p_input );
        return VLC_SUCCESS;
    }
    else if( !strcmp( psz_cmd, "marq-y" ) )
    {
        if( strlen( newval.psz_string ) > 0) 
        {
            vlc_object_t *p_pl =
                  vlc_object_find( p_this, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
            if( !p_pl )
                {
                  return VLC_ENOOBJ;
                }
            val.i_int = atoi( newval.psz_string );
            var_Set( p_pl, "marq-y", val );
             vlc_object_release( p_pl );
        }
        vlc_object_release( p_input );
        return VLC_SUCCESS;
    }
    
gbazin's avatar
 
gbazin committed
715 716 717 718 719 720
    else if( !strcmp( psz_cmd, "chapter" ) ||
             !strcmp( psz_cmd, "chapter_n" ) ||
             !strcmp( psz_cmd, "chapter_p" ) )
    {
        if( !strcmp( psz_cmd, "chapter" ) )
        {
gbazin's avatar
 
gbazin committed
721
            if ( *newval.psz_string )
gbazin's avatar
 
gbazin committed
722 723
            {
                /* Set. */
724 725
                val.i_int = atoi( newval.psz_string );
                var_Set( p_input, "chapter", val );
gbazin's avatar
 
gbazin committed
726 727 728
            }
            else
            {
729 730
                vlc_value_t val_list;

gbazin's avatar
 
gbazin committed
731
                /* Get. */
732
                var_Get( p_input, "chapter", &val );
733 734 735 736 737 738
                var_Change( p_input, "chapter", VLC_VAR_GETCHOICES,
                            &val_list, NULL );
                printf( _("Currently playing chapter %d/%d\n"),
                        val.i_int, val_list.p_list->i_count );
                var_Change( p_this, "chapter", VLC_VAR_FREELIST,
                            &val_list, NULL );
gbazin's avatar
 
gbazin committed
739 740 741 742
            }
        }
        else if( !strcmp( psz_cmd, "chapter_n" ) )
        {
743 744
            val.b_bool = VLC_TRUE;
            var_Set( p_input, "next-chapter", val );
gbazin's avatar
 
gbazin committed
745 746 747
        }
        else if( !strcmp( psz_cmd, "chapter_p" ) )
        {
748 749
            val.b_bool = VLC_TRUE;
            var_Set( p_input, "prev-chapter", val );
gbazin's avatar
 
gbazin committed
750 751 752 753 754 755 756 757 758 759 760
        }

        vlc_object_release( p_input );
        return VLC_SUCCESS;
    }
    else if( !strcmp( psz_cmd, "title" ) ||
             !strcmp( psz_cmd, "title_n" ) ||
             !strcmp( psz_cmd, "title_p" ) )
    {
        if( !strcmp( psz_cmd, "title" ) )
        {
gbazin's avatar
 
gbazin committed
761
            if ( *newval.psz_string )
gbazin's avatar
 
gbazin committed
762 763
            {
                /* Set. */
764 765
                val.i_int = atoi( newval.psz_string );
                var_Set( p_input, "title", val );
gbazin's avatar
 
gbazin committed
766 767 768
            }
            else
            {
769 770
                vlc_value_t val_list;

gbazin's avatar
 
gbazin committed
771
                /* Get. */
772
                var_Get( p_input, "title", &val );
773 774 775 776 777 778
                var_Change( p_input, "title", VLC_VAR_GETCHOICES,
                            &val_list, NULL );
                printf( _("Currently playing title %d/%d\n"),
                        val.i_int, val_list.p_list->i_count );
                var_Change( p_this, "title", VLC_VAR_FREELIST,
                            &val_list, NULL );
gbazin's avatar
 
gbazin committed
779 780 781 782
            }
        }
        else if( !strcmp( psz_cmd, "title_n" ) )
        {
783 784
            val.b_bool = VLC_TRUE;
            var_Set( p_input, "next-title", val );
gbazin's avatar
 
gbazin committed
785 786 787
        }
        else if( !strcmp( psz_cmd, "title_p" ) )
        {
788 789
            val.b_bool = VLC_TRUE;
            var_Set( p_input, "prev-title", val );
gbazin's avatar
 
gbazin committed
790 791 792 793 794 795
        }

        vlc_object_release( p_input );
        return VLC_SUCCESS;
    }

796 797
    /* Never reached. */
    return VLC_EGENERIC;
798
}
799

800 801 802
static int Playlist( vlc_object_t *p_this, char const *psz_cmd,
                     vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
803 804
    intf_thread_t *p_intf = (intf_thread_t*)p_this;
    playlist_t *p_playlist;
805

806 807
    p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
    if( !p_playlist )
    {
        return VLC_ENOOBJ;
    }

    /* Parse commands that require a playlist */
    if( !strcmp( psz_cmd, "prev" ) )
    {
        playlist_Prev( p_playlist );
    }
    else if( !strcmp( psz_cmd, "next" ) )
    {
        playlist_Next( p_playlist );
    }
    else if( !strcmp( psz_cmd, "play" ) )
    {
        playlist_Play( p_playlist );
    }
    else if( !strcmp( psz_cmd, "stop" ) )
    {
        playlist_Stop( p_playlist );
    }
830 831
    else if( !strcmp( psz_cmd, "add" ) )
    {
832
        printf( _("trying to add %s to playlist\n"), newval.psz_string );
zorglub's avatar
zorglub committed
833
        playlist_Add( p_playlist, newval.psz_string, newval.psz_string,
834 835 836 837 838 839 840 841
                      PLAYLIST_GO|PLAYLIST_APPEND, PLAYLIST_END );
    }
    else if( !strcmp( psz_cmd, "playlist" ) )
    {
        int i;
        for ( i = 0; i < p_playlist->i_size; i++ )
        {
            printf( "|%s%s   %s|\n", i == p_playlist->i_index?"*":" ",
842 843
                    p_playlist->pp_items[i]->input.psz_name,
                    p_playlist->pp_items[i]->input.psz_uri );
844 845 846
        }
        if ( i == 0 )
        {
847
            printf( _("| no entries\n") );
848 849 850 851 852 853 854
        }
    }
    /*
     * sanity check
     */
    else
    {
855
        printf( _("unknown command!\n") );
856
    }
857

gbazin's avatar
 
gbazin committed
858
    vlc_object_release( p_playlist );
859 860 861
    return VLC_SUCCESS;
}

gbazin's avatar
 
gbazin committed
862 863
static int Quit( vlc_object_t *p_this, char const *psz_cmd,
                 vlc_value_t oldval, vlc_value_t newval, void *p_data )
864 865 866 867 868
{
    p_this->p_vlc->b_die = VLC_TRUE;
    return VLC_SUCCESS;
}

gbazin's avatar
 
gbazin committed
869 870
static int Intf( vlc_object_t *p_this, char const *psz_cmd,
                 vlc_value_t oldval, vlc_value_t newval, void *p_data )
871 872 873
{
    intf_thread_t *p_newintf;

874
    p_newintf = intf_Create( p_this->p_vlc, newval.psz_string );
Sam Hocevar's avatar
Sam Hocevar committed
875

876 877 878 879 880 881 882 883 884 885 886
    if( p_newintf )
    {
        p_newintf->b_block = VLC_FALSE;
        if( intf_RunThread( p_newintf ) )
        {
            vlc_object_detach( p_newintf );
            intf_Destroy( p_newintf );
        }
    }

    return VLC_SUCCESS;
887 888
}

gbazin's avatar
 
gbazin committed
889 890
static int Volume( vlc_object_t *p_this, char const *psz_cmd,
                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
891
{
892
    intf_thread_t *p_intf = (intf_thread_t*)p_this;
893 894
    int i_error;

gbazin's avatar
 
gbazin committed
895
    if ( *newval.psz_string )
896 897
    {
        /* Set. */
gbazin's avatar
 
gbazin committed
898
        audio_volume_t i_volume = atoi( newval.psz_string );
899 900
        if ( i_volume > AOUT_VOLUME_MAX )
        {
901
            printf( _("Volume must be in the range %d-%d\n"), AOUT_VOLUME_MIN,
902 903 904
                    AOUT_VOLUME_MAX );
            i_error = VLC_EBADVAR;
        }
905
        else i_error = aout_VolumeSet( p_this, i_volume );
906 907 908 909 910
    }
    else
    {
        /* Get. */
        audio_volume_t i_volume;
911
        if ( aout_VolumeGet( p_this, &i_volume ) < 0 )
912 913 914 915 916
        {
            i_error = VLC_EGENERIC;
        }
        else
        {
917
            printf( _("Volume is %d\n"), i_volume );
918 919 920 921 922 923 924
            i_error = VLC_SUCCESS;
        }
    }

    return i_error;
}

gbazin's avatar
 
gbazin committed
925 926
static int VolumeMove( vlc_object_t *p_this, char const *psz_cmd,
                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
927
{
928
    intf_thread_t *p_intf = (intf_thread_t*)p_this;
929
    audio_volume_t i_volume;
gbazin's avatar
 
gbazin committed
930
    int i_nb_steps = atoi(newval.psz_string);
931 932 933 934 935 936 937 938 939
    int i_error = VLC_SUCCESS;

    if ( i_nb_steps <= 0 || i_nb_steps > (AOUT_VOLUME_MAX/AOUT_VOLUME_STEP) )
    {
        i_nb_steps = 1;
    }

    if ( !strcmp(psz_cmd, "volup") )
    {
940
        if ( aout_VolumeUp( p_this, i_nb_steps, &i_volume ) < 0 )
941 942 943 944
            i_error = VLC_EGENERIC;
    }
    else
    {
945
        if ( aout_VolumeDown( p_this, i_nb_steps, &i_volume ) < 0 )
946 947 948
            i_error = VLC_EGENERIC;
    }

949
    if ( !i_error ) printf( _("Volume is %d\n"), i_volume );
950 951 952
    return i_error;
}

gbazin's avatar
 
gbazin committed
953 954
static int AudioConfig( vlc_object_t *p_this, char const *psz_cmd,
                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
955
{
956
    intf_thread_t *p_intf = (intf_thread_t*)p_this;
957 958
    aout_instance_t * p_aout;
    const char * psz_variable;
gbazin's avatar
 
gbazin committed
959
    vlc_value_t val_name;
960 961 962 963 964 965 966 967 968 969 970 971 972 973
    int i_error;

    p_aout = vlc_object_find( p_this, VLC_OBJECT_AOUT, FIND_ANYWHERE );
    if ( p_aout == NULL ) return VLC_ENOOBJ;

    if ( !strcmp( psz_cmd, "adev" ) )
    {
        psz_variable = "audio-device";
    }
    else
    {
        psz_variable = "audio-channels";
    }

gbazin's avatar
 
gbazin committed
974 975 976 977 978
    /* Get the descriptive name of the variable */
    var_Change( (vlc_object_t *)p_aout, psz_variable, VLC_VAR_GETTEXT,
                 &val_name, NULL );
    if( !val_name.psz_string ) val_name.psz_string = strdup(psz_variable);

gbazin's avatar
 
gbazin committed
979
    if ( !*newval.psz_string )
980 981
    {
        /* Retrieve all registered ***. */
gbazin's avatar
 
gbazin committed
982 983
        vlc_value_t val, text;
        int i, i_value;
984 985 986 987 988 989

        if ( var_Get( (vlc_object_t *)p_aout, psz_variable, &val ) < 0 )
        {
            vlc_object_release( (vlc_object_t *)p_aout );
            return VLC_EGENERIC;
        }
gbazin's avatar
 
gbazin committed
990
        i_value = val.i_int;
991 992

        if ( var_Change( (vlc_object_t *)p_aout, psz_variable,
gbazin's avatar
 
gbazin committed
993
                         VLC_VAR_GETLIST, &val, &text ) < 0 )
994 995 996 997 998
        {
            vlc_object_release( (vlc_object_t *)p_aout );
            return VLC_EGENERIC;
        }

gbazin's avatar
 
gbazin committed
999
        printf( "+----[ %s ]\n", val_name.psz_string );
gbazin's avatar
 
gbazin committed
1000
        for ( i = 0; i < val.p_list->i_count; i++ )
1001
        {
gbazin's avatar
 
gbazin committed
1002 1003
            if ( i_value == val.p_list->p_values[i].i_int )
                printf( "| %i - %s *\n", val.p_list->p_values[i].i_int,
1004
                        text.p_list->p_values[i].psz_string );
1005
            else
gbazin's avatar
 
gbazin committed
1006
                printf( "| %i - %s\n", val.p_list->p_values[i].i_int,
1007
                        text.p_list->p_values[i].psz_string );
1008 1009
        }
        var_Change( (vlc_object_t *)p_aout, psz_variable, VLC_VAR_FREELIST,
gbazin's avatar
 
gbazin committed
1010
                    &val, &text );