rc.c 37.6 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
static int  Playlist     ( vlc_object_t *, char const *,
                           vlc_value_t, vlc_value_t, void * );
78
79
static int  Other        ( vlc_object_t *, char const *,
                           vlc_value_t, vlc_value_t, void * );
gbazin's avatar
   
gbazin committed
80
81
82
83
84
85
86
87
88
89
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 * );
90

91
92
93
94
struct intf_sys_t
{
    int i_socket_listen;
    int i_socket;
95
    char *psz_unix_path;
96
97
    vlc_bool_t b_extend;
    
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#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 );
}

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

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

127
#define UNIX_TEXT N_("UNIX socket command input")
128
129
#define UNIX_LONGTEXT N_("Accept commands over a Unix socket rather than " \
                         "stdin." )
130

131
#define HOST_TEXT N_("TCP command input")
132
#define HOST_LONGTEXT N_("Accept commands over a socket rather than stdin. " \
133
            "You can set the address and port the interface will bind to." )
134
135
136
#define EXTEND_TEXT N_("Extended help")
#define EXTEND_LONGTEXT N_("List additional commands.")
            
137

138
139
140
141
142
143
144
145
146
#ifdef WIN32
#define QUIET_TEXT N_("Do not open a DOS command box interface")
#define QUIET_LONGTEXT N_( \
    "By default the rc interface plugin will start a DOS command box. " \
    "Enabling the quiet mode will not bring this command box but can also " \
    "be pretty annoying when you want to stop VLC and no video window is " \
    "open." )
#endif

147
vlc_module_begin();
gbazin's avatar
   
gbazin committed
148
    set_description( _("Remote control interface") );
149
    add_bool( "rc-show-pos", 0, NULL, POS_TEXT, POS_LONGTEXT, VLC_TRUE );
Sam Hocevar's avatar
Sam Hocevar committed
150
#ifdef HAVE_ISATTY
151
    add_bool( "rc-fake-tty", 0, NULL, TTY_TEXT, TTY_LONGTEXT, VLC_TRUE );
Sam Hocevar's avatar
Sam Hocevar committed
152
#endif
153
    add_string( "rc-unix", 0, NULL, UNIX_TEXT, UNIX_LONGTEXT, VLC_TRUE );
154
    add_string( "rc-host", 0, NULL, HOST_TEXT, HOST_LONGTEXT, VLC_TRUE );
155
156
157
158

#ifdef WIN32
    add_bool( "rc-quiet", 0, NULL, QUIET_TEXT, QUIET_LONGTEXT, VLC_FALSE );
#endif
159
    add_bool( "rc-extend", 0, NULL, EXTEND_TEXT, EXTEND_LONGTEXT, VLC_FALSE );
160

161
    set_capability( "interface", 20 );
162
    set_callbacks( Activate, Deactivate );
163
164
165
166
167
168
169
170
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;
171
    char *psz_host, *psz_unix_path;
172
    int i_socket = -1;
173

gbazin's avatar
   
gbazin committed
174
#if defined(HAVE_ISATTY) && !defined(WIN32)
175
    /* Check that stdin is a TTY */
176
    if( !config_GetInt( p_intf, "rc-fake-tty" ) && !isatty( 0 ) )
177
178
    {
        msg_Warn( p_intf, "fd 0 is not a TTY" );
179
        return VLC_EGENERIC;
180
181
182
    }
#endif

183
184
    psz_unix_path = config_GetPsz( p_intf, "rc-unix" );
    if( psz_unix_path )
185
    {
186
#ifndef PF_LOCAL
187
        msg_Warn( p_intf, "your OS doesn't support filesystem sockets" );
188
        free( psz_unix_path );
189
190
191
192
193
194
195
196
197
        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" );

198
        if( (i_socket = socket( PF_LOCAL, SOCK_STREAM, 0 ) ) < 0 )
199
200
        {
            msg_Warn( p_intf, "can't open socket: %s", strerror(errno) );
201
            free( psz_unix_path );
202
203
204
            return VLC_EGENERIC;
        }

205
206
207
        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';
208
209
210
211
212
213

        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) );
214
215
            free( psz_unix_path );
            net_Close( i_socket );
216
217
218
219
220
221
            return VLC_EGENERIC;
        }

        if( ( i_ret = listen( i_socket, 1 ) ) < 0 )
        {
            msg_Warn( p_intf, "can't listen on socket: %s", strerror(errno));
222
223
            free( psz_unix_path );
            net_Close( i_socket );
224
225
226
227
            return VLC_EGENERIC;
        }
#endif
    }
228
229
230

    if( ( i_socket == -1) &&
        ( psz_host = config_GetPsz( p_intf, "rc-host" ) ) != NULL )
231
232
233
    {
        vlc_url_t url;

234
235
236
237
238
        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)
239
        {
240
241
            msg_Warn( p_intf, "can't listen to %s port %i",
                      url.psz_host, url.i_port );
242
243
244
245
246
247
            vlc_UrlClean( &url );
            free( psz_host );
            return VLC_EGENERIC;
        }

        vlc_UrlClean( &url );
248
        free( psz_host );
249
250
251
252
253
254
255
256
257
258
259
    }

    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;
260
    p_intf->p_sys->psz_unix_path = psz_unix_path;
261

262
263
264
265
266
    /* Non-buffered stdout */
    setvbuf( stdout, (char *)NULL, _IOLBF, 0 );

    p_intf->pf_run = Run;

267
268
269
#ifdef WIN32
    if( !config_GetInt( p_intf, "rc-quiet" ) ) { CONSOLE_INTRO_MSG; }
#else
gbazin's avatar
   
gbazin committed
270
    CONSOLE_INTRO_MSG;
271
#endif
272

273
    printf( _("Remote control interface initialized, `h' for help\n") );
274
    return VLC_SUCCESS;
275
276
}

277
278
279
280
281
282
283
284
285
286
287
/*****************************************************************************
 * 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 );
288
289
290
291
292
293
294
    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 );
    }
295
296
297
    free( p_intf->p_sys );
}

298
299
300
301
302
303
304
305
306
/*****************************************************************************
 * 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;
307
    playlist_t *     p_playlist;
308
309

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

312
    int        i_size = 0;
Laurent Aimar's avatar
Laurent Aimar committed
313
314
    int        i_oldpos = 0;
    int        i_newpos;
315

316
    p_buffer[0] = 0;
gbazin's avatar
   
gbazin committed
317
318
    p_input = NULL;
    p_playlist = NULL;
319
320
 
    p_intf->p_sys->b_extend = config_GetInt( p_intf, "rc-extend" );
321
    /* Register commands that will be cleaned up upon object destruction */
gbazin's avatar
   
gbazin committed
322
323
324
325
326
    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 );

327
328
329
330
    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
331
332
333
334
335
336
337
338
    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 );
339
  
340
341
    var_Create( p_intf, "marq-marquee", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
    var_AddCallback( p_intf, "marq-marquee", Other, NULL );
342
    var_Create( p_intf, "marq-x", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
343
    var_AddCallback( p_intf, "marq-x", Other, NULL );
344
    var_Create( p_intf, "marq-y", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
345
    var_AddCallback( p_intf, "marq-y", Other, NULL );
zorglub's avatar
zorglub committed
346
    var_Create( p_intf, "marq-timeout", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
347
    var_AddCallback( p_intf, "marq-timeout", Other, NULL );
gbazin's avatar
   
gbazin committed
348

349
350
351
352
    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
353
    var_Create( p_intf, "title", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
354
    var_AddCallback( p_intf, "title", Input, NULL );
gbazin's avatar
   
gbazin committed
355
    var_Create( p_intf, "title_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
356
    var_AddCallback( p_intf, "title_n", Input, NULL );
gbazin's avatar
   
gbazin committed
357
    var_Create( p_intf, "title_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
358
    var_AddCallback( p_intf, "title_p", Input, NULL );
gbazin's avatar
   
gbazin committed
359
    var_Create( p_intf, "chapter", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
360
    var_AddCallback( p_intf, "chapter", Input, NULL );
gbazin's avatar
   
gbazin committed
361
    var_Create( p_intf, "chapter_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
362
    var_AddCallback( p_intf, "chapter_n", Input, NULL );
gbazin's avatar
   
gbazin committed
363
    var_Create( p_intf, "chapter_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
364
    var_AddCallback( p_intf, "chapter_p", Input, NULL );
gbazin's avatar
   
gbazin committed
365
366
367
368
369
370
371
372
373
374
375

    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 );
376

gbazin's avatar
   
gbazin committed
377
378
#ifdef WIN32
    /* Get the file descriptor of the console input */
379
380
    p_intf->p_sys->hConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
    if( p_intf->p_sys->hConsoleIn == INVALID_HANDLE_VALUE )
gbazin's avatar
   
gbazin committed
381
    {
382
        msg_Err( p_intf, "Couldn't open STD_INPUT_HANDLE" );
gbazin's avatar
   
gbazin committed
383
        p_intf->b_die = VLC_TRUE;
gbazin's avatar
   
gbazin committed
384
385
386
    }
#endif

387
388
    while( !p_intf->b_die )
    {
389
390
        char *psz_cmd, *psz_arg;
        vlc_bool_t b_complete;
391

392
393
        if( p_intf->p_sys->i_socket_listen != - 1 &&
            p_intf->p_sys->i_socket == -1 )
394
        {
395
396
            p_intf->p_sys->i_socket =
                net_Accept( p_intf, p_intf->p_sys->i_socket_listen, 0 );
397
398
        }

399
400
        b_complete = ReadCommand( p_intf, p_buffer, &i_size );

401
402
403
        /* Manage the input part */
        if( p_input == NULL )
        {
404
405
406
407
408
409
410
411
412
            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 );
413
                if( p_input )
414
415
416
417
418
                {
                    p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
                                                           FIND_PARENT );
                }
            }
419
420
421
422
423
424
425
        }
        else if( p_input->b_dead )
        {
            vlc_object_release( p_input );
            p_input = NULL;
        }

426
        if( p_input && b_showpos )
427
        {
Laurent Aimar's avatar
Laurent Aimar committed
428
429
            i_newpos = 100 * var_GetFloat( p_input, "position" );
            if( i_oldpos != i_newpos )
430
            {
Laurent Aimar's avatar
Laurent Aimar committed
431
432
                i_oldpos = i_newpos;
                printf( "pos: %d%%\n", i_newpos );
433
434
435
436
            }
        }

        /* Is there something to do? */
437
438
439
440
441
442
        if( !b_complete ) continue;


        /* Skip heading spaces */
        psz_cmd = p_buffer;
        while( *psz_cmd == ' ' )
443
        {
444
445
            psz_cmd++;
        }
446

447
448
449
450
451
452
453
        /* 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 == ' ' )
454
            {
455
                psz_arg++;
456
            }
457
458
459
460
461
462
463
464
465
466
467
        }
        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;
468

469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
            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 );
484
485
486
487
488
            if( i_ret != 0 )
            {
                printf( _("%s: returned %i (%s)\n"),
                         psz_cmd, i_ret, vlc_error( i_ret ) );
            }
489
        }
zorglub's avatar
zorglub committed
490
491
492
493
494
495
496
497
498
        else if( !strcmp( psz_cmd, "logout" ) )
        {
            /* Close connection */
            if( p_intf->p_sys->i_socket != -1 )
            {
                net_Close( p_intf->p_sys->i_socket );
            }
            p_intf->p_sys->i_socket = -1;
        }
499
500
501
        else if( !strcmp( psz_cmd, "info" ) )
        {
            if( p_input )
502
            {
503
504
505
                int i, j;
                vlc_mutex_lock( &p_input->input.p_item->lock );
                for ( i = 0; i < p_input->input.p_item->i_categories; i++ )
506
                {
507
508
509
510
511
512
513
514
515
516
517
518
                    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" );
519
                }
520
521
                printf( _("+----[ end of stream info ]\n") );
                vlc_mutex_unlock( &p_input->input.p_item->lock );
522
            }
523
            else
524
            {
525
                printf( _("no input\n") );
Sam Hocevar's avatar
Sam Hocevar committed
526
            }
527
        }
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
        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 );
            }
        }
576
577
578
579
580
        else switch( psz_cmd[0] )
        {
        case 'f':
        case 'F':
            if( p_input )
Sam Hocevar's avatar
Sam Hocevar committed
581
            {
582
583
584
                vout_thread_t *p_vout;
                p_vout = vlc_object_find( p_input,
                                          VLC_OBJECT_VOUT, FIND_CHILD );
585

586
                if( p_vout )
587
                {
588
589
                    p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
                    vlc_object_release( p_vout );
590
591
                }
            }
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
            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");
            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");
628
629
            if (p_intf->p_sys->b_extend)
            {
630
	           printf(_("| marq-marquee STRING  . . overlay STRING in video\n"));
631
632
633
634
635
               printf(_("| marq-x X . . . . . .offset of marquee, from left\n"));
               printf(_("| marq-y Y . . . . . . offset of marquee, from top\n"));
               printf(_("| marq-timeout T. . . . .timeout of marquee, in ms\n"));
               printf("| \n");
            }    
636
            printf(_("| help . . . . . . . . . . . . . this help message\n"));
zorglub's avatar
zorglub committed
637
            printf(_("| logout . . . . . .exit (if in socket connection)\n"));
638
639
640
641
642
643
644
645
646
647
648
649
            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;
650
        }
651
652
653

        /* Command processed */
        i_size = 0; p_buffer[0] = 0;
654
655
656
657
658
659
    }

    if( p_input )
    {
        vlc_object_release( p_input );
        p_input = NULL;
660
    }
661

662
663
664
665
    if( p_playlist )
    {
        vlc_object_release( p_playlist );
        p_playlist = NULL;
666
    }
667
668
}

669
670
static int Input( vlc_object_t *p_this, char const *psz_cmd,
                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
671
{
672
673
    intf_thread_t *p_intf = (intf_thread_t*)p_this;
    input_thread_t *p_input;
674
    vlc_value_t     val;
675
676

    p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
677
    if( !p_input ) return VLC_ENOOBJ;
678
679
680
681

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

        var_Set( p_input, "state", val );
685
686
687
        vlc_object_release( p_input );
        return VLC_SUCCESS;
    }
688
689
    else if( !strcmp( psz_cmd, "seek" ) )
    {
690
691
692
        if( strlen( newval.psz_string ) > 0 &&
            newval.psz_string[strlen( newval.psz_string ) - 1] == '%' )
        {
693
694
            val.f_float = (float)atoi( newval.psz_string ) / 100.0;
            var_Set( p_input, "position", val );
695
696
697
        }
        else
        {
gbazin's avatar
gbazin committed
698
            val.i_time = ((int64_t)atoi( newval.psz_string )) * 1000000;
699
            var_Set( p_input, "time", val );
700
701
702
        }
        vlc_object_release( p_input );
        return VLC_SUCCESS;
703
    }
704
   
gbazin's avatar
   
gbazin committed
705
706
707
708
709
710
    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
711
            if ( *newval.psz_string )
gbazin's avatar
   
gbazin committed
712
713
            {
                /* Set. */
714
715
                val.i_int = atoi( newval.psz_string );
                var_Set( p_input, "chapter", val );
gbazin's avatar
   
gbazin committed
716
717
718
            }
            else
            {
719
720
                vlc_value_t val_list;

gbazin's avatar
   
gbazin committed
721
                /* Get. */
722
                var_Get( p_input, "chapter", &val );
723
724
725
726
727
728
                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
729
730
731
732
            }
        }
        else if( !strcmp( psz_cmd, "chapter_n" ) )
        {
733
734
            val.b_bool = VLC_TRUE;
            var_Set( p_input, "next-chapter", val );
gbazin's avatar
   
gbazin committed
735
736
737
        }
        else if( !strcmp( psz_cmd, "chapter_p" ) )
        {
738
739
            val.b_bool = VLC_TRUE;
            var_Set( p_input, "prev-chapter", val );
gbazin's avatar
   
gbazin committed
740
741
742
743
744
745
746
747
748
749
750
        }

        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
751
            if ( *newval.psz_string )
gbazin's avatar
   
gbazin committed
752
753
            {
                /* Set. */
754
755
                val.i_int = atoi( newval.psz_string );
                var_Set( p_input, "title", val );
gbazin's avatar
   
gbazin committed
756
757
758
            }
            else
            {
759
760
                vlc_value_t val_list;

gbazin's avatar
   
gbazin committed
761
                /* Get. */
762
                var_Get( p_input, "title", &val );
763
764
765
766
767
768
                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
769
770
771
772
            }
        }
        else if( !strcmp( psz_cmd, "title_n" ) )
        {
773
774
            val.b_bool = VLC_TRUE;
            var_Set( p_input, "next-title", val );
gbazin's avatar
   
gbazin committed
775
776
777
        }
        else if( !strcmp( psz_cmd, "title_p" ) )
        {
778
779
            val.b_bool = VLC_TRUE;
            var_Set( p_input, "prev-title", val );
gbazin's avatar
   
gbazin committed
780
781
782
783
784
785
        }

        vlc_object_release( p_input );
        return VLC_SUCCESS;
    }

786
787
    /* Never reached. */
    return VLC_EGENERIC;
788
}
789

790
791
792
static int Playlist( vlc_object_t *p_this, char const *psz_cmd,
                     vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
793
794
    intf_thread_t *p_intf = (intf_thread_t*)p_this;
    playlist_t *p_playlist;
795

796
797
    p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
    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 );
    }
820
821
    else if( !strcmp( psz_cmd, "add" ) )
    {
822
        printf( _("trying to add %s to playlist\n"), newval.psz_string );
zorglub's avatar
zorglub committed
823
        playlist_Add( p_playlist, newval.psz_string, newval.psz_string,
824
825
826
827
828
829
830
831
                      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?"*":" ",
832
833
                    p_playlist->pp_items[i]->input.psz_name,
                    p_playlist->pp_items[i]->input.psz_uri );
834
835
836
        }
        if ( i == 0 )
        {
837
            printf( _("| no entries\n") );
838
839
        }
    }
840
841
842
843
844
845
846
847
848
849
850
851
852
 
    /*
     * sanity check
     */
    else
    {
        printf( _("unknown command!\n") );
    }

    vlc_object_release( p_playlist );
    return VLC_SUCCESS;
}

853
static int Other( vlc_object_t *p_this, char const *psz_cmd,
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
                     vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    intf_thread_t *p_intf = (intf_thread_t*)p_this;
    vlc_object_t *p_pl;
    vlc_value_t     val;

    p_pl = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
    if( !p_pl )
    {
        return VLC_ENOOBJ;
    }

    /* Parse miscellaneous commands */
    if( !strcmp( psz_cmd, "marq-marquee" ) )
869
870
871
872
    {
        if( strlen( newval.psz_string ) > 0 )
        {
            val.psz_string = newval.psz_string;
873
            var_Set( p_pl, "marq-marquee", val );
874
875
876
877
        }
        else 
        {
	        val.psz_string = "";
878
	        var_Set( p_pl, "marq-marquee", val);
879
880
881
882
883
884
885
        }
    }
    else if( !strcmp( psz_cmd, "marq-x" ) )
    {
        if( strlen( newval.psz_string ) > 0) 
        {
            val.i_int = atoi( newval.psz_string );
886
            var_Set( p_pl, "marq-x", val );
887
888
889
890
891
892
893
        }
    }
    else if( !strcmp( psz_cmd, "marq-y" ) )
    {
        if( strlen( newval.psz_string ) > 0) 
        {
            val.i_int = atoi( newval.psz_string );
894
            var_Set( p_pl, "marq-y", val );
895
896
897
898
899
900
901
        }
    }
    else if( !strcmp( psz_cmd, "marq-timeout" ) )
    {
        if( strlen( newval.psz_string ) > 0) 
        {
            val.i_int = atoi( newval.psz_string );
902
            var_Set( p_pl, "marq-timeout", val );
903
904
905
        }
    }
 
906
907
908
909
910
    /*
     * sanity check
     */
    else
    {
911
        printf( _("unknown command!\n") );
912
    }
913

914
    vlc_object_release( p_pl );
915
916
917
    return VLC_SUCCESS;
}

gbazin's avatar
   
gbazin committed
918
919
static int Quit( vlc_object_t *p_this, char const *psz_cmd,
                 vlc_value_t oldval, vlc_value_t newval, void *p_data )
920
921
922
923
924
{
    p_this->p_vlc->b_die = VLC_TRUE;
    return VLC_SUCCESS;
}

gbazin's avatar
   
gbazin committed
925
926
static int Intf( vlc_object_t *p_this, char const *psz_cmd,
                 vlc_value_t oldval, vlc_value_t newval, void *p_data )
927
928
929
{
    intf_thread_t *p_newintf;

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

932
933
934
935
936
937
938
939
940
941
942
    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;
943
944
}

gbazin's avatar
   
gbazin committed
945
946
static int Volume( vlc_object_t *p_this, char const *psz_cmd,
                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
947
{
948
    intf_thread_t *p_intf = (intf_thread_t*)p_this;
949
950
    int i_error;

gbazin's avatar
   
gbazin committed
951
    if ( *newval.psz_string )
952
953
    {
        /* Set. */
gbazin's avatar
   
gbazin committed
954
        audio_volume_t i_volume = atoi( newval.psz_string );
955
956
        if ( i_volume > AOUT_VOLUME_MAX )
        {
957
            printf( _("Volume must be in the range %d-%d\n"), AOUT_VOLUME_MIN,
958
959
960
                    AOUT_VOLUME_MAX );
            i_error = VLC_EBADVAR;
        }
961
        else i_error = aout_VolumeSet( p_this, i_volume );
962
963
964
965
966
    }
    else
    {
        /* Get. */
        audio_volume_t i_volume;
967
        if ( aout_VolumeGet( p_this, &i_volume ) < 0 )
968
969
970
971
972
        {
            i_error = VLC_EGENERIC;
        }
        else
        {
973
            printf( _("Volume is %d\n"), i_volume );
974
975
976
977
978
979
980
            i_error = VLC_SUCCESS;
        }
    }

    return i_error;
}

gbazin's avatar
   
gbazin committed
981
982
static int VolumeMove( vlc_object_t *p_this, char const *psz_cmd,
                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
983
{
984
    intf_thread_t *p_intf = (intf_thread_t*)p_this;
985
    audio_volume_t i_volume;
gbazin's avatar
   
gbazin committed
986
    int i_nb_steps = atoi(newval.psz_string);
987
988
989
990
991
992
993
994
995
    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") )
    {
996
        if ( aout_VolumeUp( p_this, i_nb_steps, &i_volume ) < 0 )
997
998
999
1000
            i_error = VLC_EGENERIC;
    }
    else
    {
For faster browsing, not all history is shown. View entire blame