rc.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:74k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * rc.c : remote control stdin/stdout module for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2004-2009 the VideoLAN team
  5.  * $Id: 2fb6fc81e312523f0018e50428835df85c7a7fc2 $
  6.  *
  7.  * Author: Peter Surda <shurdeek@panorama.sth.ac.at>
  8.  *         Jean-Paul Saman <jpsaman #_at_# m2x _replaceWith#dot_ nl>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #ifdef HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <vlc_common.h>
  31. #include <vlc_plugin.h>
  32. #include <errno.h>                                                 /* ENOMEM */
  33. #include <ctype.h>
  34. #include <signal.h>
  35. #include <assert.h>
  36. #include <vlc_interface.h>
  37. #include <vlc_aout.h>
  38. #include <vlc_vout.h>
  39. #include <vlc_osd.h>
  40. #include <vlc_playlist.h>
  41. #ifdef HAVE_UNISTD_H
  42. #    include <unistd.h>
  43. #endif
  44. #ifdef HAVE_SYS_TIME_H
  45. #    include <sys/time.h>
  46. #endif
  47. #include <sys/types.h>
  48. #include <vlc_network.h>
  49. #include "vlc_url.h"
  50. #include <vlc_charset.h>
  51. #if defined(PF_UNIX) && !defined(PF_LOCAL)
  52. #    define PF_LOCAL PF_UNIX
  53. #endif
  54. #if defined(AF_LOCAL) && ! defined(WIN32)
  55. #    include <sys/un.h>
  56. #endif
  57. #define MAX_LINE_LENGTH 1024
  58. #define STATUS_CHANGE "status change: "
  59. /* input_state_e from <vlc_input.h> */
  60. static const char *ppsz_input_state[] = {
  61.     [INIT_S] = N_("Initializing"),
  62.     [OPENING_S] = N_("Opening"),
  63.     [PLAYING_S] = N_("Play"),
  64.     [PAUSE_S] = N_("Pause"),
  65.     [END_S] = N_("End"),
  66.     [ERROR_S] = N_("Error"),
  67. };
  68. /*****************************************************************************
  69.  * Local prototypes
  70.  *****************************************************************************/
  71. static int  Activate     ( vlc_object_t * );
  72. static void Deactivate   ( vlc_object_t * );
  73. static void Run          ( intf_thread_t * );
  74. static void Help         ( intf_thread_t *, bool );
  75. static void RegisterCallbacks( intf_thread_t * );
  76. static bool ReadCommand( intf_thread_t *, char *, int * );
  77. static input_item_t *parse_MRL( intf_thread_t *, char * );
  78. static int  Input        ( vlc_object_t *, char const *,
  79.                            vlc_value_t, vlc_value_t, void * );
  80. static int  Playlist     ( vlc_object_t *, char const *,
  81.                            vlc_value_t, vlc_value_t, void * );
  82. static int  Quit         ( vlc_object_t *, char const *,
  83.                            vlc_value_t, vlc_value_t, void * );
  84. static int  Intf         ( vlc_object_t *, char const *,
  85.                            vlc_value_t, vlc_value_t, void * );
  86. static int  Volume       ( vlc_object_t *, char const *,
  87.                            vlc_value_t, vlc_value_t, void * );
  88. static int  VolumeMove   ( vlc_object_t *, char const *,
  89.                            vlc_value_t, vlc_value_t, void * );
  90. static int  VideoConfig  ( vlc_object_t *, char const *,
  91.                            vlc_value_t, vlc_value_t, void * );
  92. static int  AudioConfig  ( vlc_object_t *, char const *,
  93.                            vlc_value_t, vlc_value_t, void * );
  94. static int  Menu         ( vlc_object_t *, char const *,
  95.                            vlc_value_t, vlc_value_t, void * );
  96. static int  Statistics   ( vlc_object_t *, char const *,
  97.                            vlc_value_t, vlc_value_t, void * );
  98. static int updateStatistics( intf_thread_t *, input_item_t *);
  99. /* Status Callbacks */
  100. static int TimeOffsetChanged( vlc_object_t *, char const *,
  101.                               vlc_value_t, vlc_value_t , void * );
  102. static int VolumeChanged    ( vlc_object_t *, char const *,
  103.                               vlc_value_t, vlc_value_t, void * );
  104. static int StateChanged     ( vlc_object_t *, char const *,
  105.                               vlc_value_t, vlc_value_t, void * );
  106. static int RateChanged      ( vlc_object_t *, char const *,
  107.                               vlc_value_t, vlc_value_t, void * );
  108. struct intf_sys_t
  109. {
  110.     int *pi_socket_listen;
  111.     int i_socket;
  112.     char *psz_unix_path;
  113.     /* status changes */
  114.     vlc_mutex_t       status_lock;
  115.     playlist_status_t i_last_state;
  116. #ifdef WIN32
  117.     HANDLE hConsoleIn;
  118.     bool b_quiet;
  119. #endif
  120. };
  121. #define msg_rc( ... ) __msg_rc( p_intf, __VA_ARGS__ )
  122. LIBVLC_FORMAT(2, 3)
  123. static void __msg_rc( intf_thread_t *p_intf, const char *psz_fmt, ... )
  124. {
  125.     va_list args;
  126.     char fmt_eol[strlen (psz_fmt) + 3];
  127.     snprintf (fmt_eol, sizeof (fmt_eol), "%srn", psz_fmt);
  128.     va_start( args, psz_fmt );
  129.     if( p_intf->p_sys->i_socket == -1 )
  130.         utf8_vfprintf( stdout, fmt_eol, args );
  131.     else
  132.         net_vaPrintf( p_intf, p_intf->p_sys->i_socket, NULL, fmt_eol, args );
  133.     va_end( args );
  134. }
  135. /*****************************************************************************
  136.  * Module descriptor
  137.  *****************************************************************************/
  138. #define POS_TEXT N_("Show stream position")
  139. #define POS_LONGTEXT N_("Show the current position in seconds within the " 
  140.                         "stream from time to time." )
  141. #define TTY_TEXT N_("Fake TTY")
  142. #define TTY_LONGTEXT N_("Force the rc module to use stdin as if it was a TTY.")
  143. #define UNIX_TEXT N_("UNIX socket command input")
  144. #define UNIX_LONGTEXT N_("Accept commands over a Unix socket rather than " 
  145.                          "stdin." )
  146. #define HOST_TEXT N_("TCP command input")
  147. #define HOST_LONGTEXT N_("Accept commands over a socket rather than stdin. " 
  148.             "You can set the address and port the interface will bind to." )
  149. #ifdef WIN32
  150. #define QUIET_TEXT N_("Do not open a DOS command box interface")
  151. #define QUIET_LONGTEXT N_( 
  152.     "By default the rc interface plugin will start a DOS command box. " 
  153.     "Enabling the quiet mode will not bring this command box but can also " 
  154.     "be pretty annoying when you want to stop VLC and no video window is " 
  155.     "open." )
  156. #endif
  157. vlc_module_begin ()
  158.     set_shortname( N_("RC"))
  159.     set_category( CAT_INTERFACE )
  160.     set_subcategory( SUBCAT_INTERFACE_MAIN )
  161.     set_description( N_("Remote control interface") )
  162.     add_bool( "rc-show-pos", 0, NULL, POS_TEXT, POS_LONGTEXT, true )
  163. #ifdef WIN32
  164.     add_bool( "rc-quiet", 0, NULL, QUIET_TEXT, QUIET_LONGTEXT, false )
  165. #else
  166. #if defined (HAVE_ISATTY)
  167.     add_bool( "rc-fake-tty", 0, NULL, TTY_TEXT, TTY_LONGTEXT, true )
  168. #endif
  169.     add_string( "rc-unix", 0, NULL, UNIX_TEXT, UNIX_LONGTEXT, true )
  170. #endif
  171.     add_string( "rc-host", 0, NULL, HOST_TEXT, HOST_LONGTEXT, true )
  172.     set_capability( "interface", 20 )
  173.     set_callbacks( Activate, Deactivate )
  174. vlc_module_end ()
  175. /*****************************************************************************
  176.  * Activate: initialize and create stuff
  177.  *****************************************************************************/
  178. static int Activate( vlc_object_t *p_this )
  179. {
  180.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  181.     char *psz_host, *psz_unix_path = NULL;
  182.     int  *pi_socket = NULL;
  183. #ifndef WIN32
  184. #if defined(HAVE_ISATTY)
  185.     /* Check that stdin is a TTY */
  186.     if( !config_GetInt( p_intf, "rc-fake-tty" ) && !isatty( 0 ) )
  187.     {
  188.         msg_Warn( p_intf, "fd 0 is not a TTY" );
  189.         return VLC_EGENERIC;
  190.     }
  191. #endif
  192.     psz_unix_path = config_GetPsz( p_intf, "rc-unix" );
  193.     if( psz_unix_path )
  194.     {
  195.         int i_socket;
  196. #ifndef AF_LOCAL
  197.         msg_Warn( p_intf, "your OS doesn't support filesystem sockets" );
  198.         free( psz_unix_path );
  199.         return VLC_EGENERIC;
  200. #else
  201.         struct sockaddr_un addr;
  202.         memset( &addr, 0, sizeof(struct sockaddr_un) );
  203.         msg_Dbg( p_intf, "trying UNIX socket" );
  204.         if( (i_socket = socket( PF_LOCAL, SOCK_STREAM, 0 ) ) < 0 )
  205.         {
  206.             msg_Warn( p_intf, "can't open socket: %m" );
  207.             free( psz_unix_path );
  208.             return VLC_EGENERIC;
  209.         }
  210.         addr.sun_family = AF_LOCAL;
  211.         strncpy( addr.sun_path, psz_unix_path, sizeof( addr.sun_path ) );
  212.         addr.sun_path[sizeof( addr.sun_path ) - 1] = '';
  213.         if (bind (i_socket, (struct sockaddr *)&addr, sizeof (addr))
  214.          && (errno == EADDRINUSE)
  215.          && connect (i_socket, (struct sockaddr *)&addr, sizeof (addr))
  216.          && (errno == ECONNREFUSED))
  217.         {
  218.             msg_Info (p_intf, "Removing dead UNIX socket: %s", psz_unix_path);
  219.             unlink (psz_unix_path);
  220.             if (bind (i_socket, (struct sockaddr *)&addr, sizeof (addr)))
  221.             {
  222.                 msg_Err (p_intf, "cannot bind UNIX socket at %s: %m",
  223.                          psz_unix_path);
  224.                 free (psz_unix_path);
  225.                 net_Close (i_socket);
  226.                 return VLC_EGENERIC;
  227.             }
  228.         }
  229.         if( listen( i_socket, 1 ) )
  230.         {
  231.             msg_Warn( p_intf, "can't listen on socket: %m");
  232.             free( psz_unix_path );
  233.             net_Close( i_socket );
  234.             return VLC_EGENERIC;
  235.         }
  236.         /* FIXME: we need a core function to merge listening sockets sets */
  237.         pi_socket = calloc( 2, sizeof( int ) );
  238.         if( pi_socket == NULL )
  239.         {
  240.             free( psz_unix_path );
  241.             net_Close( i_socket );
  242.             return VLC_ENOMEM;
  243.         }
  244.         pi_socket[0] = i_socket;
  245.         pi_socket[1] = -1;
  246. #endif /* AF_LOCAL */
  247.     }
  248. #endif /* !WIN32 */
  249.     if( ( pi_socket == NULL ) &&
  250.         ( psz_host = config_GetPsz( p_intf, "rc-host" ) ) != NULL )
  251.     {
  252.         vlc_url_t url;
  253.         vlc_UrlParse( &url, psz_host, 0 );
  254.         msg_Dbg( p_intf, "base: %s, port: %d", url.psz_host, url.i_port );
  255.         pi_socket = net_ListenTCP(p_this, url.psz_host, url.i_port);
  256.         if( pi_socket == NULL )
  257.         {
  258.             msg_Warn( p_intf, "can't listen to %s port %i",
  259.                       url.psz_host, url.i_port );
  260.             vlc_UrlClean( &url );
  261.             free( psz_host );
  262.             return VLC_EGENERIC;
  263.         }
  264.         vlc_UrlClean( &url );
  265.         free( psz_host );
  266.     }
  267.     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
  268.     if( !p_intf->p_sys )
  269.         return VLC_ENOMEM;
  270.     p_intf->p_sys->pi_socket_listen = pi_socket;
  271.     p_intf->p_sys->i_socket = -1;
  272.     p_intf->p_sys->psz_unix_path = psz_unix_path;
  273.     vlc_mutex_init( &p_intf->p_sys->status_lock );
  274.     p_intf->p_sys->i_last_state = PLAYLIST_STOPPED;
  275.     /* Non-buffered stdout */
  276.     setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
  277.     p_intf->pf_run = Run;
  278. #ifdef WIN32
  279.     p_intf->p_sys->b_quiet = config_GetInt( p_intf, "rc-quiet" );
  280.     if( !p_intf->p_sys->b_quiet ) { CONSOLE_INTRO_MSG; }
  281. #else
  282.     CONSOLE_INTRO_MSG;
  283. #endif
  284.     msg_rc( "%s", _("Remote control interface initialized. Type `help' for help.") );
  285.     return VLC_SUCCESS;
  286. }
  287. /*****************************************************************************
  288.  * Deactivate: uninitialize and cleanup
  289.  *****************************************************************************/
  290. static void Deactivate( vlc_object_t *p_this )
  291. {
  292.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  293.     net_ListenClose( p_intf->p_sys->pi_socket_listen );
  294.     if( p_intf->p_sys->i_socket != -1 )
  295.         net_Close( p_intf->p_sys->i_socket );
  296.     if( p_intf->p_sys->psz_unix_path != NULL )
  297.     {
  298. #if defined(AF_LOCAL) && !defined(WIN32)
  299.         unlink( p_intf->p_sys->psz_unix_path );
  300. #endif
  301.         free( p_intf->p_sys->psz_unix_path );
  302.     }
  303.     vlc_mutex_destroy( &p_intf->p_sys->status_lock );
  304.     free( p_intf->p_sys );
  305. }
  306. /*****************************************************************************
  307.  * RegisterCallbacks: Register callbacks to dynamic variables
  308.  *****************************************************************************/
  309. static void RegisterCallbacks( intf_thread_t *p_intf )
  310. {
  311.     /* Register commands that will be cleaned up upon object destruction */
  312. #define ADD( name, type, target )                                   
  313.     var_Create( p_intf, name, VLC_VAR_ ## type | VLC_VAR_ISCOMMAND ); 
  314.     var_AddCallback( p_intf, name, target, NULL );
  315.     ADD( "quit", VOID, Quit )
  316.     ADD( "intf", STRING, Intf )
  317.     ADD( "add", STRING, Playlist )
  318.     ADD( "repeat", STRING, Playlist )
  319.     ADD( "loop", STRING, Playlist )
  320.     ADD( "random", STRING, Playlist )
  321.     ADD( "enqueue", STRING, Playlist )
  322.     ADD( "playlist", VOID, Playlist )
  323.     ADD( "sort", VOID, Playlist )
  324.     ADD( "play", VOID, Playlist )
  325.     ADD( "stop", VOID, Playlist )
  326.     ADD( "clear", VOID, Playlist )
  327.     ADD( "prev", VOID, Playlist )
  328.     ADD( "next", VOID, Playlist )
  329.     ADD( "goto", INTEGER, Playlist )
  330.     ADD( "status", INTEGER, Playlist )
  331.     /* OSD menu commands */
  332.     ADD(  "menu", STRING, Menu )
  333.     /* DVD commands */
  334.     ADD( "pause", VOID, Input )
  335.     ADD( "seek", INTEGER, Input )
  336.     ADD( "title", STRING, Input )
  337.     ADD( "title_n", VOID, Input )
  338.     ADD( "title_p", VOID, Input )
  339.     ADD( "chapter", STRING, Input )
  340.     ADD( "chapter_n", VOID, Input )
  341.     ADD( "chapter_p", VOID, Input )
  342.     ADD( "fastforward", VOID, Input )
  343.     ADD( "rewind", VOID, Input )
  344.     ADD( "faster", VOID, Input )
  345.     ADD( "slower", VOID, Input )
  346.     ADD( "normal", VOID, Input )
  347.     ADD( "atrack", STRING, Input )
  348.     ADD( "vtrack", STRING, Input )
  349.     ADD( "strack", STRING, Input )
  350.     /* video commands */
  351.     ADD( "vratio", STRING, VideoConfig )
  352.     ADD( "vcrop", STRING, VideoConfig )
  353.     ADD( "vzoom", STRING, VideoConfig )
  354.     ADD( "snapshot", VOID, VideoConfig )
  355.     /* audio commands */
  356.     ADD( "volume", STRING, Volume )
  357.     ADD( "volup", STRING, VolumeMove )
  358.     ADD( "voldown", STRING, VolumeMove )
  359.     ADD( "adev", STRING, AudioConfig )
  360.     ADD( "achan", STRING, AudioConfig )
  361.     /* misc menu commands */
  362.     ADD( "stats", BOOL, Statistics )
  363. #undef ADD
  364. }
  365. /*****************************************************************************
  366.  * Run: rc thread
  367.  *****************************************************************************
  368.  * This part of the interface is in a separate thread so that we can call
  369.  * exec() from within it without annoying the rest of the program.
  370.  *****************************************************************************/
  371. static void Run( intf_thread_t *p_intf )
  372. {
  373.     input_thread_t * p_input;
  374.     playlist_t *     p_playlist;
  375.     char p_buffer[ MAX_LINE_LENGTH + 1 ];
  376.     bool b_showpos = config_GetInt( p_intf, "rc-show-pos" );
  377.     bool b_longhelp = false;
  378.     int  i_size = 0;
  379.     int  i_oldpos = 0;
  380.     int  i_newpos;
  381.     int  canc = vlc_savecancel();
  382.     p_buffer[0] = 0;
  383.     p_input = NULL;
  384.     p_playlist = NULL;
  385.     /* Register commands that will be cleaned up upon object destruction */
  386.     RegisterCallbacks( p_intf );
  387.     /* status callbacks */
  388.     /* Listen to audio volume updates */
  389.     var_AddCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, p_intf );
  390. #ifdef WIN32
  391.     /* Get the file descriptor of the console input */
  392.     p_intf->p_sys->hConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
  393.     if( p_intf->p_sys->hConsoleIn == INVALID_HANDLE_VALUE )
  394.     {
  395.         msg_Err( p_intf, "couldn't find user input handle" );
  396.         vlc_object_kill( p_intf );
  397.     }
  398. #endif
  399.     while( vlc_object_alive( p_intf ) )
  400.     {
  401.         char *psz_cmd, *psz_arg;
  402.         bool b_complete;
  403.         if( p_intf->p_sys->pi_socket_listen != NULL &&
  404.             p_intf->p_sys->i_socket == -1 )
  405.         {
  406.             p_intf->p_sys->i_socket =
  407.                 net_Accept( p_intf, p_intf->p_sys->pi_socket_listen,
  408.                             INTF_IDLE_SLEEP );
  409.             if( p_intf->p_sys->i_socket == -1 ) continue;
  410.         }
  411.         b_complete = ReadCommand( p_intf, p_buffer, &i_size );
  412.         /* Manage the input part */
  413.         if( p_input == NULL )
  414.         {
  415.             if( p_playlist )
  416.             {
  417.                 p_input = vlc_object_find( p_playlist, VLC_OBJECT_INPUT,
  418.                                                        FIND_CHILD );
  419.             }
  420.             else
  421.             {
  422.                 p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
  423.                                                    FIND_ANYWHERE );
  424.                 if( p_input )
  425.                 {
  426.                     p_playlist = pl_Hold( p_input );
  427.                 }
  428.             }
  429.             /* New input has been registered */
  430.             if( p_input )
  431.             {
  432.                 if( !p_input->b_dead || vlc_object_alive (p_input) )
  433.                 {
  434.                     char *psz_uri =
  435.                             input_item_GetURI( input_GetItem( p_input ) );
  436.                     msg_rc( STATUS_CHANGE "( new input: %s )", psz_uri );
  437.                     free( psz_uri );
  438.                     msg_rc( STATUS_CHANGE "( audio volume: %d )",
  439.                             config_GetInt( p_intf, "volume" ));
  440.                 }
  441.                 var_AddCallback( p_input, "state", StateChanged, p_intf );
  442.                 var_AddCallback( p_input, "rate-faster", RateChanged, p_intf );
  443.                 var_AddCallback( p_input, "rate-slower", RateChanged, p_intf );
  444.                 var_AddCallback( p_input, "rate", RateChanged, p_intf );
  445.                 var_AddCallback( p_input, "time-offset", TimeOffsetChanged,
  446.                                  p_intf );
  447.             }
  448.         }
  449.         else if( p_input->b_dead )
  450.         {
  451.             var_DelCallback( p_input, "state", StateChanged, p_intf );
  452.             var_DelCallback( p_input, "rate-faster", RateChanged, p_intf );
  453.             var_DelCallback( p_input, "rate-slower", RateChanged, p_intf );
  454.             var_DelCallback( p_input, "rate", RateChanged, p_intf );
  455.             var_DelCallback( p_input, "time-offset", TimeOffsetChanged,
  456.                              p_intf );
  457.             vlc_object_release( p_input );
  458.             p_input = NULL;
  459.             if( p_playlist )
  460.             {
  461.                 PL_LOCK;
  462.                 p_intf->p_sys->i_last_state = (int) PLAYLIST_STOPPED;
  463.                 msg_rc( STATUS_CHANGE "( stop state: 0 )" );
  464.                 PL_UNLOCK;
  465.             }
  466.         }
  467.         if( (p_input != NULL) && !p_input->b_dead && vlc_object_alive (p_input) &&
  468.             (p_playlist != NULL) )
  469.         {
  470.             PL_LOCK;
  471.             int status = playlist_Status( p_playlist );
  472.             if( p_intf->p_sys->i_last_state != status )
  473.             {
  474.                 if( status == PLAYLIST_STOPPED )
  475.                 {
  476.                     p_intf->p_sys->i_last_state = PLAYLIST_STOPPED;
  477.                     msg_rc( STATUS_CHANGE "( stop state: 5 )" );
  478.                 }
  479.                 else if( status == PLAYLIST_RUNNING )
  480.                 {
  481.                     p_intf->p_sys->i_last_state = PLAYLIST_RUNNING;
  482.                     msg_rc( STATUS_CHANGE "( play state: 3 )" );
  483.                 }
  484.                 else if( status == PLAYLIST_PAUSED )
  485.                 {
  486.                     p_intf->p_sys->i_last_state = PLAYLIST_PAUSED;
  487.                     msg_rc( STATUS_CHANGE "( pause state: 4 )" );
  488.                 }
  489.             }
  490.             PL_UNLOCK;
  491.         }
  492.         if( p_input && b_showpos )
  493.         {
  494.             i_newpos = 100 * var_GetFloat( p_input, "position" );
  495.             if( i_oldpos != i_newpos )
  496.             {
  497.                 i_oldpos = i_newpos;
  498.                 msg_rc( "pos: %d%%", i_newpos );
  499.             }
  500.         }
  501.         /* Is there something to do? */
  502.         if( !b_complete ) continue;
  503.         /* Skip heading spaces */
  504.         psz_cmd = p_buffer;
  505.         while( *psz_cmd == ' ' )
  506.         {
  507.             psz_cmd++;
  508.         }
  509.         /* Split psz_cmd at the first space and make sure that
  510.          * psz_arg is valid */
  511.         psz_arg = strchr( psz_cmd, ' ' );
  512.         if( psz_arg )
  513.         {
  514.             *psz_arg++ = 0;
  515.             while( *psz_arg == ' ' )
  516.             {
  517.                 psz_arg++;
  518.             }
  519.         }
  520.         else
  521.         {
  522.             psz_arg = (char*)"";
  523.         }
  524.         /* module specfic commands: @<module name> <command> <args...> */
  525.         if( *psz_cmd == '@' && *psz_arg )
  526.         {
  527.             /* Parse miscellaneous commands */
  528.             char *psz_alias = psz_cmd + 1;
  529.             char *psz_mycmd = strdup( psz_arg );
  530.             char *psz_myarg = strchr( psz_mycmd, ' ' );
  531.             char *psz_msg;
  532.             if( !psz_myarg )
  533.             {
  534.                 msg_rc( "Not enough parameters." );
  535.             }
  536.             else
  537.             {
  538.                 *psz_myarg = '';
  539.                 psz_myarg ++;
  540.                 var_Command( p_intf, psz_alias, psz_mycmd, psz_myarg,
  541.                              &psz_msg );
  542.                 if( psz_msg )
  543.                 {
  544.                     msg_rc( "%s", psz_msg );
  545.                     free( psz_msg );
  546.                 }
  547.             }
  548.             free( psz_mycmd );
  549.         }
  550.         /* If the user typed a registered local command, try it */
  551.         else if( var_Type( p_intf, psz_cmd ) & VLC_VAR_ISCOMMAND )
  552.         {
  553.             vlc_value_t val;
  554.             int i_ret;
  555.             val.psz_string = psz_arg;
  556.             i_ret = var_Set( p_intf, psz_cmd, val );
  557.             msg_rc( "%s: returned %i (%s)",
  558.                     psz_cmd, i_ret, vlc_error( i_ret ) );
  559.         }
  560.         /* Or maybe it's a global command */
  561.         else if( var_Type( p_intf->p_libvlc, psz_cmd ) & VLC_VAR_ISCOMMAND )
  562.         {
  563.             vlc_value_t val;
  564.             int i_ret;
  565.             val.psz_string = psz_arg;
  566.             /* FIXME: it's a global command, but we should pass the
  567.              * local object as an argument, not p_intf->p_libvlc. */
  568.             i_ret = var_Set( p_intf->p_libvlc, psz_cmd, val );
  569.             if( i_ret != 0 )
  570.             {
  571.                 msg_rc( "%s: returned %i (%s)",
  572.                          psz_cmd, i_ret, vlc_error( i_ret ) );
  573.             }
  574.         }
  575.         else if( !strcmp( psz_cmd, "logout" ) )
  576.         {
  577.             /* Close connection */
  578.             if( p_intf->p_sys->i_socket != -1 )
  579.             {
  580.                 net_Close( p_intf->p_sys->i_socket );
  581.             }
  582.             p_intf->p_sys->i_socket = -1;
  583.         }
  584.         else if( !strcmp( psz_cmd, "info" ) )
  585.         {
  586.             if( p_input )
  587.             {
  588.                 int i, j;
  589.                 vlc_mutex_lock( &input_GetItem(p_input)->lock );
  590.                 for ( i = 0; i < input_GetItem(p_input)->i_categories; i++ )
  591.                 {
  592.                     info_category_t *p_category = input_GetItem(p_input)
  593.                                                         ->pp_categories[i];
  594.                     msg_rc( "+----[ %s ]", p_category->psz_name );
  595.                     msg_rc( "| " );
  596.                     for ( j = 0; j < p_category->i_infos; j++ )
  597.                     {
  598.                         info_t *p_info = p_category->pp_infos[j];
  599.                         msg_rc( "| %s: %s", p_info->psz_name,
  600.                                 p_info->psz_value );
  601.                     }
  602.                     msg_rc( "| " );
  603.                 }
  604.                 msg_rc( "+----[ end of stream info ]" );
  605.                 vlc_mutex_unlock( &input_GetItem(p_input)->lock );
  606.             }
  607.             else
  608.             {
  609.                 msg_rc( "no input" );
  610.             }
  611.         }
  612.         else if( !strcmp( psz_cmd, "is_playing" ) )
  613.         {
  614.             if( ! p_input )
  615.             {
  616.                 msg_rc( "0" );
  617.             }
  618.             else
  619.             {
  620.                 msg_rc( "1" );
  621.             }
  622.         }
  623.         else if( !strcmp( psz_cmd, "get_time" ) )
  624.         {
  625.             if( ! p_input )
  626.             {
  627.                 msg_rc("0");
  628.             }
  629.             else
  630.             {
  631.                 vlc_value_t time;
  632.                 var_Get( p_input, "time", &time );
  633.                 msg_rc( "%"PRIu64, time.i_time / 1000000);
  634.             }
  635.         }
  636.         else if( !strcmp( psz_cmd, "get_length" ) )
  637.         {
  638.             if( ! p_input )
  639.             {
  640.                 msg_rc("0");
  641.             }
  642.             else
  643.             {
  644.                 vlc_value_t time;
  645.                 var_Get( p_input, "length", &time );
  646.                 msg_rc( "%"PRIu64, time.i_time / 1000000);
  647.             }
  648.         }
  649.         else if( !strcmp( psz_cmd, "get_title" ) )
  650.         {
  651.             if( ! p_input )
  652.             {
  653.                 msg_rc("%s", "");
  654.             }
  655.             else
  656.             {
  657.                 msg_rc( "%s", input_GetItem(p_input)->psz_name );
  658.             }
  659.         }
  660.         else if( !strcmp( psz_cmd, "longhelp" ) || !strncmp( psz_cmd, "h", 1 )
  661.                  || !strncmp( psz_cmd, "H", 1 ) || !strncmp( psz_cmd, "?", 1 ) )
  662.         {
  663.             if( !strcmp( psz_cmd, "longhelp" ) || !strncmp( psz_cmd, "H", 1 ) )
  664.                  b_longhelp = true;
  665.             else b_longhelp = false;
  666.             Help( p_intf, b_longhelp );
  667.         }
  668.         else if( !strcmp( psz_cmd, "key" ) || !strcmp( psz_cmd, "hotkey" ) )
  669.         {
  670.             var_SetInteger( p_intf->p_libvlc, "key-pressed",
  671.                             config_GetInt( p_intf, psz_arg ) );
  672.         }
  673.         else switch( psz_cmd[0] )
  674.         {
  675.         case 'f':
  676.         case 'F':
  677.             if( p_input )
  678.             {
  679.                 vout_thread_t *p_vout;
  680.                 p_vout = vlc_object_find( p_input,
  681.                                           VLC_OBJECT_VOUT, FIND_CHILD );
  682.                 if( p_vout )
  683.                 {
  684.                     vlc_value_t val;
  685.                     bool b_update = false;
  686.                     var_Get( p_vout, "fullscreen", &val );
  687.                     val.b_bool = !val.b_bool;
  688.                     if( !strncmp( psz_arg, "on", 2 )
  689.                         && ( val.b_bool == true ) )
  690.                     {
  691.                         b_update = true;
  692.                         val.b_bool = true;
  693.                     }
  694.                     else if( !strncmp( psz_arg, "off", 3 )
  695.                              && ( val.b_bool == false ) )
  696.                     {
  697.                         b_update = true;
  698.                         val.b_bool = false;
  699.                     }
  700.                     else if( strncmp( psz_arg, "off", 3 )
  701.                              && strncmp( psz_arg, "on", 2 ) )
  702.                         b_update = true;
  703.                     if( b_update ) var_Set( p_vout, "fullscreen", val );
  704.                     vlc_object_release( p_vout );
  705.                 }
  706.             }
  707.             break;
  708.         case 's':
  709.         case 'S':
  710.             ;
  711.             break;
  712.         case '':
  713.             /* Ignore empty lines */
  714.             break;
  715.         default:
  716.             msg_rc(_("Unknown command `%s'. Type `help' for help."), psz_cmd);
  717.             break;
  718.         }
  719.         /* Command processed */
  720.         i_size = 0; p_buffer[0] = 0;
  721.     }
  722.     msg_rc( STATUS_CHANGE "( stop state: 0 )" );
  723.     msg_rc( STATUS_CHANGE "( quit )" );
  724.     if( p_input )
  725.     {
  726.         var_DelCallback( p_input, "state", StateChanged, p_intf );
  727.         var_DelCallback( p_input, "rate-faster", RateChanged, p_intf );
  728.         var_DelCallback( p_input, "rate-slower", RateChanged, p_intf );
  729.         var_DelCallback( p_input, "rate", RateChanged, p_intf );
  730.         var_DelCallback( p_input, "time-offset", TimeOffsetChanged, p_intf );
  731.         vlc_object_release( p_input );
  732.         p_input = NULL;
  733.     }
  734.     if( p_playlist )
  735.     {
  736.         vlc_object_release( p_playlist );
  737.         p_playlist = NULL;
  738.     }
  739.     var_DelCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, p_intf );
  740.     vlc_restorecancel( canc );
  741. }
  742. static void Help( intf_thread_t *p_intf, bool b_longhelp)
  743. {
  744.     msg_rc("%s", _("+----[ Remote control commands ]"));
  745.     msg_rc(  "| ");
  746.     msg_rc("%s", _("| add XYZ  . . . . . . . . . . . . add XYZ to playlist"));
  747.     msg_rc("%s", _("| enqueue XYZ  . . . . . . . . . queue XYZ to playlist"));
  748.     msg_rc("%s", _("| playlist . . . . .  show items currently in playlist"));
  749.     msg_rc("%s", _("| play . . . . . . . . . . . . . . . . . . play stream"));
  750.     msg_rc("%s", _("| stop . . . . . . . . . . . . . . . . . . stop stream"));
  751.     msg_rc("%s", _("| next . . . . . . . . . . . . . .  next playlist item"));
  752.     msg_rc("%s", _("| prev . . . . . . . . . . . .  previous playlist item"));
  753.     msg_rc("%s", _("| goto . . . . . . . . . . . . . .  goto item at index"));
  754.     msg_rc("%s", _("| repeat [on|off] . . . .  toggle playlist item repeat"));
  755.     msg_rc("%s", _("| loop [on|off] . . . . . . . . . toggle playlist loop"));
  756.     msg_rc("%s", _("| random [on|off] . . . . . . .  toggle random jumping"));
  757.     msg_rc("%s", _("| clear . . . . . . . . . . . . . . clear the playlist"));
  758.     msg_rc("%s", _("| status . . . . . . . . . . . current playlist status"));
  759.     msg_rc("%s", _("| title [X]  . . . . . . set/get title in current item"));
  760.     msg_rc("%s", _("| title_n  . . . . . . . .  next title in current item"));
  761.     msg_rc("%s", _("| title_p  . . . . . .  previous title in current item"));
  762.     msg_rc("%s", _("| chapter [X]  . . . . set/get chapter in current item"));
  763.     msg_rc("%s", _("| chapter_n  . . . . . .  next chapter in current item"));
  764.     msg_rc("%s", _("| chapter_p  . . . .  previous chapter in current item"));
  765.     msg_rc(  "| ");
  766.     msg_rc("%s", _("| seek X . . . seek in seconds, for instance `seek 12'"));
  767.     msg_rc("%s", _("| pause  . . . . . . . . . . . . . . . .  toggle pause"));
  768.     msg_rc("%s", _("| fastforward  . . . . . . . .  .  set to maximum rate"));
  769.     msg_rc("%s", _("| rewind  . . . . . . . . . . . .  set to minimum rate"));
  770.     msg_rc("%s", _("| faster . . . . . . . . . .  faster playing of stream"));
  771.     msg_rc("%s", _("| slower . . . . . . . . . .  slower playing of stream"));
  772.     msg_rc("%s", _("| normal . . . . . . . . . .  normal playing of stream"));
  773.     msg_rc("%s", _("| f [on|off] . . . . . . . . . . . . toggle fullscreen"));
  774.     msg_rc("%s", _("| info . . . . .  information about the current stream"));
  775.     msg_rc("%s", _("| stats  . . . . . . . .  show statistical information"));
  776.     msg_rc("%s", _("| get_time . . seconds elapsed since stream's beginning"));
  777.     msg_rc("%s", _("| is_playing . . . .  1 if a stream plays, 0 otherwise"));
  778.     msg_rc("%s", _("| get_title . . . . .  the title of the current stream"));
  779.     msg_rc("%s", _("| get_length . . . .  the length of the current stream"));
  780.     msg_rc(  "| ");
  781.     msg_rc("%s", _("| volume [X] . . . . . . . . . .  set/get audio volume"));
  782.     msg_rc("%s", _("| volup [X]  . . . . . . .  raise audio volume X steps"));
  783.     msg_rc("%s", _("| voldown [X]  . . . . . .  lower audio volume X steps"));
  784.     msg_rc("%s", _("| adev [X] . . . . . . . . . . .  set/get audio device"));
  785.     msg_rc("%s", _("| achan [X]. . . . . . . . . .  set/get audio channels"));
  786.     msg_rc("%s", _("| atrack [X] . . . . . . . . . . . set/get audio track"));
  787.     msg_rc("%s", _("| vtrack [X] . . . . . . . . . . . set/get video track"));
  788.     msg_rc("%s", _("| vratio [X]  . . . . . . . set/get video aspect ratio"));
  789.     msg_rc("%s", _("| vcrop [X]  . . . . . . . . . . .  set/get video crop"));
  790.     msg_rc("%s", _("| vzoom [X]  . . . . . . . . . . .  set/get video zoom"));
  791.     msg_rc("%s", _("| snapshot . . . . . . . . . . . . take video snapshot"));
  792.     msg_rc("%s", _("| strack [X] . . . . . . . . . set/get subtitles track"));
  793.     msg_rc("%s", _("| key [hotkey name] . . . . . .  simulate hotkey press"));
  794.     msg_rc("%s", _("| menu . . [on|off|up|down|left|right|select] use menu"));
  795.     msg_rc(  "| ");
  796.     if (b_longhelp)
  797.     {
  798.         msg_rc("%s", _("| @name marq-marquee  STRING  . . overlay STRING in video"));
  799.         msg_rc("%s", _("| @name marq-x X . . . . . . . . . . . .offset from left"));
  800.         msg_rc("%s", _("| @name marq-y Y . . . . . . . . . . . . offset from top"));
  801.         msg_rc("%s", _("| @name marq-position #. . .  .relative position control"));
  802.         msg_rc("%s", _("| @name marq-color # . . . . . . . . . . font color, RGB"));
  803.         msg_rc("%s", _("| @name marq-opacity # . . . . . . . . . . . . . opacity"));
  804.         msg_rc("%s", _("| @name marq-timeout T. . . . . . . . . . timeout, in ms"));
  805.         msg_rc("%s", _("| @name marq-size # . . . . . . . . font size, in pixels"));
  806.         msg_rc(  "| ");
  807.         msg_rc("%s", _("| @name logo-file STRING . . .the overlay file path/name"));
  808.         msg_rc("%s", _("| @name logo-x X . . . . . . . . . . . .offset from left"));
  809.         msg_rc("%s", _("| @name logo-y Y . . . . . . . . . . . . offset from top"));
  810.         msg_rc("%s", _("| @name logo-position #. . . . . . . . relative position"));
  811.         msg_rc("%s", _("| @name logo-transparency #. . . . . . . . .transparency"));
  812.         msg_rc(  "| ");
  813.         msg_rc("%s", _("| @name mosaic-alpha # . . . . . . . . . . . . . . alpha"));
  814.         msg_rc("%s", _("| @name mosaic-height #. . . . . . . . . . . . . .height"));
  815.         msg_rc("%s", _("| @name mosaic-width # . . . . . . . . . . . . . . width"));
  816.         msg_rc("%s", _("| @name mosaic-xoffset # . . . .top left corner position"));
  817.         msg_rc("%s", _("| @name mosaic-yoffset # . . . .top left corner position"));
  818.         msg_rc("%s", _("| @name mosaic-offsets x,y(,x,y)*. . . . list of offsets"));
  819.         msg_rc("%s", _("| @name mosaic-align 0..2,4..6,8..10. . .mosaic alignment"));
  820.         msg_rc("%s", _("| @name mosaic-vborder # . . . . . . . . vertical border"));
  821.         msg_rc("%s", _("| @name mosaic-hborder # . . . . . . . horizontal border"));
  822.         msg_rc("%s", _("| @name mosaic-position {0=auto,1=fixed} . . . .position"));
  823.         msg_rc("%s", _("| @name mosaic-rows #. . . . . . . . . . .number of rows"));
  824.         msg_rc("%s", _("| @name mosaic-cols #. . . . . . . . . . .number of cols"));
  825.         msg_rc("%s", _("| @name mosaic-order id(,id)* . . . . order of pictures "));
  826.         msg_rc("%s", _("| @name mosaic-keep-aspect-ratio {0,1} . . .aspect ratio"));
  827.         msg_rc(  "| ");
  828.     }
  829.     msg_rc("%s", _("| help . . . . . . . . . . . . . . . this help message"));
  830.     msg_rc("%s", _("| longhelp . . . . . . . . . . . a longer help message"));
  831.     msg_rc("%s", _("| logout . . . . . . .  exit (if in socket connection)"));
  832.     msg_rc("%s", _("| quit . . . . . . . . . . . . . . . . . . .  quit vlc"));
  833.     msg_rc(  "| ");
  834.     msg_rc("%s", _("+----[ end of help ]"));
  835. }
  836. /********************************************************************
  837.  * Status callback routines
  838.  ********************************************************************/
  839. static int TimeOffsetChanged( vlc_object_t *p_this, char const *psz_cmd,
  840.     vlc_value_t oldval, vlc_value_t newval, void *p_data )
  841. {
  842.     VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd);
  843.     VLC_UNUSED(oldval); VLC_UNUSED(newval);
  844.     intf_thread_t *p_intf = (intf_thread_t*)p_data;
  845.     input_thread_t *p_input = NULL;
  846.     vlc_mutex_lock( &p_intf->p_sys->status_lock );
  847.     p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
  848.     if( p_input )
  849.     {
  850.         msg_rc( STATUS_CHANGE "( time-offset: %"PRId64"s )",
  851.                 (var_GetTime( p_input, "time-offset" )/1000000) );
  852.         vlc_object_release( p_input );
  853.     }
  854.     vlc_mutex_unlock( &p_intf->p_sys->status_lock );
  855.     return VLC_SUCCESS;
  856. }
  857. static int VolumeChanged( vlc_object_t *p_this, char const *psz_cmd,
  858.     vlc_value_t oldval, vlc_value_t newval, void *p_data )
  859. {
  860.     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(newval);
  861.     intf_thread_t *p_intf = (intf_thread_t*)p_data;
  862.     vlc_mutex_lock( &p_intf->p_sys->status_lock );
  863.     msg_rc( STATUS_CHANGE "( audio volume: %d )",
  864.             config_GetInt( p_this, "volume") );
  865.     vlc_mutex_unlock( &p_intf->p_sys->status_lock );
  866.     return VLC_SUCCESS;
  867. }
  868. static int StateChanged( vlc_object_t *p_this, char const *psz_cmd,
  869.     vlc_value_t oldval, vlc_value_t newval, void *p_data )
  870. {
  871.     VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
  872.     intf_thread_t *p_intf = (intf_thread_t*)p_data;
  873.     playlist_t    *p_playlist = NULL;
  874.     char cmd[6];
  875.     vlc_mutex_lock( &p_intf->p_sys->status_lock );
  876.     p_playlist = pl_Hold( p_intf );
  877.     PL_LOCK;
  878.     int i_status = playlist_Status( p_playlist );
  879.     PL_UNLOCK;
  880.     pl_Release( p_intf );
  881.     switch( i_status )
  882.     {
  883.     case PLAYLIST_STOPPED:
  884.         strcpy( cmd, "stop" );
  885.         break;
  886.     case PLAYLIST_RUNNING:
  887.         strcpy( cmd, "play" );
  888.         break;
  889.     case PLAYLIST_PAUSED:
  890.         strcpy( cmd, "pause" );
  891.         break;
  892.     default:
  893.         cmd[0] = '';
  894.     } /* var_GetInteger( p_input, "state" )  */
  895.     msg_rc( STATUS_CHANGE "( %s state: %d ): %s", cmd, newval.i_int,
  896.             ppsz_input_state[ newval.i_int ] );
  897.     vlc_mutex_unlock( &p_intf->p_sys->status_lock );
  898.     return VLC_SUCCESS;
  899. }
  900. static int RateChanged( vlc_object_t *p_this, char const *psz_cmd,
  901.     vlc_value_t oldval, vlc_value_t newval, void *p_data )
  902. {
  903.     VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd);
  904.     VLC_UNUSED(oldval); VLC_UNUSED(newval);
  905.     intf_thread_t *p_intf = (intf_thread_t*)p_data;
  906.     input_thread_t *p_input = NULL;
  907.     vlc_mutex_lock( &p_intf->p_sys->status_lock );
  908.     p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
  909.     if( p_input )
  910.     {
  911.         msg_rc( STATUS_CHANGE "( new rate: %d )",
  912.                 var_GetInteger( p_input, "rate" ) );
  913.         vlc_object_release( p_input );
  914.     }
  915.     vlc_mutex_unlock( &p_intf->p_sys->status_lock );
  916.     return VLC_SUCCESS;
  917. }
  918. /********************************************************************
  919.  * Command routines
  920.  ********************************************************************/
  921. static int Input( vlc_object_t *p_this, char const *psz_cmd,
  922.                   vlc_value_t oldval, vlc_value_t newval, void *p_data )
  923. {
  924.     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
  925.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  926.     input_thread_t *p_input;
  927.     vlc_value_t     val;
  928.     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
  929.     if( !p_input ) return VLC_ENOOBJ;
  930.     var_Get( p_input, "state", &val );
  931.     if( ( val.i_int == PAUSE_S ) &&
  932.         ( strcmp( psz_cmd, "pause" ) != 0 ) )
  933.     {
  934.         msg_rc( "%s", _("Press menu select or pause to continue.") );
  935.         vlc_object_release( p_input );
  936.         return VLC_EGENERIC;
  937.     }
  938.     /* Parse commands that only require an input */
  939.     if( !strcmp( psz_cmd, "pause" ) )
  940.     {
  941.         val.i_int = config_GetInt( p_intf, "key-play-pause" );
  942.         var_Set( p_intf->p_libvlc, "key-pressed", val );
  943.         vlc_object_release( p_input );
  944.         return VLC_SUCCESS;
  945.     }
  946.     else if( !strcmp( psz_cmd, "seek" ) )
  947.     {
  948.         if( strlen( newval.psz_string ) > 0 &&
  949.             newval.psz_string[strlen( newval.psz_string ) - 1] == '%' )
  950.         {
  951.             val.f_float = (float)atof( newval.psz_string ) / 100.0;
  952.             var_Set( p_input, "position", val );
  953.         }
  954.         else
  955.         {
  956.             val.i_time = ((int64_t)atoi( newval.psz_string )) * 1000000;
  957.             var_Set( p_input, "time", val );
  958.         }
  959.         vlc_object_release( p_input );
  960.         return VLC_SUCCESS;
  961.     }
  962.     else if ( !strcmp( psz_cmd, "fastforward" ) )
  963.     {
  964.         if( var_GetBool( p_input, "can-rate" ) )
  965.         {
  966.             int i_rate = var_GetInteger( p_input, "rate" );
  967.             i_rate = (i_rate < 0) ? -i_rate : i_rate / 2;
  968.             var_SetInteger( p_input, "rate", i_rate );
  969.         }
  970.         else
  971.         {
  972.             val.i_int = config_GetInt( p_intf, "key-jump+extrashort" );
  973.             var_Set( p_intf->p_libvlc, "key-pressed", val );
  974.         }
  975.         vlc_object_release( p_input );
  976.         return VLC_SUCCESS;
  977.     }
  978.     else if ( !strcmp( psz_cmd, "rewind" ) )
  979.     {
  980.         if( var_GetBool( p_input, "can-rewind" ) )
  981.         {
  982.             int i_rate = var_GetInteger( p_input, "rate" );
  983.             i_rate = (i_rate > 0) ? -i_rate : i_rate / 2;
  984.             var_SetInteger( p_input, "rate", i_rate );
  985.         }
  986.         else
  987.         {
  988.             val.i_int = config_GetInt( p_intf, "key-jump-extrashort" );
  989.             var_Set( p_intf->p_libvlc, "key-pressed", val );
  990.         }
  991.         vlc_object_release( p_input );
  992.         return VLC_SUCCESS;
  993.     }
  994.     else if ( !strcmp( psz_cmd, "faster" ) )
  995.     {
  996.         var_Set( p_input, "rate-faster", val );
  997.         vlc_object_release( p_input );
  998.         return VLC_SUCCESS;
  999.     }
  1000.     else if ( !strcmp( psz_cmd, "slower" ) )
  1001.     {
  1002.         var_Set( p_input, "rate-slower", val );
  1003.         vlc_object_release( p_input );
  1004.         return VLC_SUCCESS;
  1005.     }
  1006.     else if ( !strcmp( psz_cmd, "normal" ) )
  1007.     {
  1008.         val.i_int = INPUT_RATE_DEFAULT;
  1009.         var_Set( p_input, "rate", val );
  1010.         vlc_object_release( p_input );
  1011.         return VLC_SUCCESS;
  1012.     }
  1013.     else if( !strcmp( psz_cmd, "chapter" ) ||
  1014.              !strcmp( psz_cmd, "chapter_n" ) ||
  1015.              !strcmp( psz_cmd, "chapter_p" ) )
  1016.     {
  1017.         if( !strcmp( psz_cmd, "chapter" ) )
  1018.         {
  1019.             if ( *newval.psz_string )
  1020.             {
  1021.                 /* Set. */
  1022.                 val.i_int = atoi( newval.psz_string );
  1023.                 var_Set( p_input, "chapter", val );
  1024.             }
  1025.             else
  1026.             {
  1027.                 vlc_value_t val_list;
  1028.                 /* Get. */
  1029.                 var_Get( p_input, "chapter", &val );
  1030.                 var_Change( p_input, "chapter", VLC_VAR_GETCHOICES,
  1031.                             &val_list, NULL );
  1032.                 msg_rc( "Currently playing chapter %d/%d.",
  1033.                         val.i_int, val_list.p_list->i_count );
  1034.                 var_Change( p_this, "chapter", VLC_VAR_FREELIST,
  1035.                             &val_list, NULL );
  1036.             }
  1037.         }
  1038.         else if( !strcmp( psz_cmd, "chapter_n" ) )
  1039.             var_SetVoid( p_input, "next-chapter" );
  1040.         else if( !strcmp( psz_cmd, "chapter_p" ) )
  1041.             var_SetVoid( p_input, "prev-chapter" );
  1042.         vlc_object_release( p_input );
  1043.         return VLC_SUCCESS;
  1044.     }
  1045.     else if( !strcmp( psz_cmd, "title" ) ||
  1046.              !strcmp( psz_cmd, "title_n" ) ||
  1047.              !strcmp( psz_cmd, "title_p" ) )
  1048.     {
  1049.         if( !strcmp( psz_cmd, "title" ) )
  1050.         {
  1051.             if ( *newval.psz_string )
  1052.             {
  1053.                 /* Set. */
  1054.                 val.i_int = atoi( newval.psz_string );
  1055.                 var_Set( p_input, "title", val );
  1056.             }
  1057.             else
  1058.             {
  1059.                 vlc_value_t val_list;
  1060.                 /* Get. */
  1061.                 var_Get( p_input, "title", &val );
  1062.                 var_Change( p_input, "title", VLC_VAR_GETCHOICES,
  1063.                             &val_list, NULL );
  1064.                 msg_rc( "Currently playing title %d/%d.",
  1065.                         val.i_int, val_list.p_list->i_count );
  1066.                 var_Change( p_this, "title", VLC_VAR_FREELIST,
  1067.                             &val_list, NULL );
  1068.             }
  1069.         }
  1070.         else if( !strcmp( psz_cmd, "title_n" ) )
  1071.             var_SetVoid( p_input, "next-title" );
  1072.         else if( !strcmp( psz_cmd, "title_p" ) )
  1073.             var_SetVoid( p_input, "prev-title" );
  1074.         vlc_object_release( p_input );
  1075.         return VLC_SUCCESS;
  1076.     }
  1077.     else if(    !strcmp( psz_cmd, "atrack" )
  1078.              || !strcmp( psz_cmd, "vtrack" )
  1079.              || !strcmp( psz_cmd, "strack" ) )
  1080.     {
  1081.         const char *psz_variable;
  1082.         vlc_value_t val_name;
  1083.         int i_error;
  1084.         if( !strcmp( psz_cmd, "atrack" ) )
  1085.         {
  1086.             psz_variable = "audio-es";
  1087.         }
  1088.         else if( !strcmp( psz_cmd, "vtrack" ) )
  1089.         {
  1090.             psz_variable = "video-es";
  1091.         }
  1092.         else
  1093.         {
  1094.             psz_variable = "spu-es";
  1095.         }
  1096.         /* Get the descriptive name of the variable */
  1097.         var_Change( p_input, psz_variable, VLC_VAR_GETTEXT,
  1098.                      &val_name, NULL );
  1099.         if( !val_name.psz_string ) val_name.psz_string = strdup(psz_variable);
  1100.         if( newval.psz_string && *newval.psz_string )
  1101.         {
  1102.             /* set */
  1103.             vlc_value_t val;
  1104.             val.i_int = atoi( newval.psz_string );
  1105.             i_error = var_Set( p_input, psz_variable, val );
  1106.         }
  1107.         else
  1108.         {
  1109.             /* get */
  1110.             vlc_value_t val, text;
  1111.             int i, i_value;
  1112.             if ( var_Get( p_input, psz_variable, &val ) < 0 )
  1113.             {
  1114.                 vlc_object_release( p_input );
  1115.                 return VLC_EGENERIC;
  1116.             }
  1117.             i_value = val.i_int;
  1118.             if ( var_Change( p_input, psz_variable,
  1119.                              VLC_VAR_GETLIST, &val, &text ) < 0 )
  1120.             {
  1121.                 vlc_object_release( p_input );
  1122.                 return VLC_EGENERIC;
  1123.             }
  1124.             msg_rc( "+----[ %s ]", val_name.psz_string );
  1125.             for ( i = 0; i < val.p_list->i_count; i++ )
  1126.             {
  1127.                 if ( i_value == val.p_list->p_values[i].i_int )
  1128.                     msg_rc( "| %i - %s *", val.p_list->p_values[i].i_int,
  1129.                             text.p_list->p_values[i].psz_string );
  1130.                 else
  1131.                     msg_rc( "| %i - %s", val.p_list->p_values[i].i_int,
  1132.                             text.p_list->p_values[i].psz_string );
  1133.             }
  1134.             var_Change( p_input, psz_variable, VLC_VAR_FREELIST,
  1135.                         &val, &text );
  1136.             msg_rc( "+----[ end of %s ]", val_name.psz_string );
  1137.             free( val_name.psz_string );
  1138.             i_error = VLC_SUCCESS;
  1139.         }
  1140.         vlc_object_release( p_input );
  1141.         return i_error;
  1142.     }
  1143.     /* Never reached. */
  1144.     vlc_object_release( p_input );
  1145.     return VLC_EGENERIC;
  1146. }
  1147. static void print_playlist( intf_thread_t *p_intf, playlist_item_t *p_item, int i_level )
  1148. {
  1149.     int i;
  1150.     char psz_buffer[MSTRTIME_MAX_SIZE];
  1151.     for( i = 0; i< p_item->i_children; i++ )
  1152.     {
  1153.         if( p_item->pp_children[i]->p_input->i_duration != -1 )
  1154.         {
  1155.             secstotimestr( psz_buffer, p_item->pp_children[i]->p_input->i_duration / 1000000 );
  1156.             msg_rc( "|%*s- %s (%s)", 2 * i_level, "", p_item->pp_children[i]->p_input->psz_name, psz_buffer );
  1157.         }
  1158.         else
  1159.             msg_rc( "|%*s- %s", 2 * i_level, "", p_item->pp_children[i]->p_input->psz_name );
  1160.         if( p_item->pp_children[i]->i_children >= 0 )
  1161.             print_playlist( p_intf, p_item->pp_children[i], i_level + 1 );
  1162.     }
  1163. }
  1164. static int Playlist( vlc_object_t *p_this, char const *psz_cmd,
  1165.                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1166. {
  1167.     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
  1168.     vlc_value_t val;
  1169.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  1170.     playlist_t *p_playlist = pl_Hold( p_this );
  1171.     input_thread_t * p_input = playlist_CurrentInput( p_playlist );
  1172.     if( p_input )
  1173.     {
  1174.         var_Get( p_input, "state", &val );
  1175.         vlc_object_release( p_input );
  1176.         if( val.i_int == PAUSE_S )
  1177.         {
  1178.             msg_rc( "%s", _("Type 'menu select' or 'pause' to continue.") );
  1179.             pl_Release( p_this );
  1180.             return VLC_EGENERIC;
  1181.         }
  1182.     }
  1183.     /* Parse commands that require a playlist */
  1184.     if( !strcmp( psz_cmd, "prev" ) )
  1185.     {
  1186.         playlist_Prev( p_playlist );
  1187.     }
  1188.     else if( !strcmp( psz_cmd, "next" ) )
  1189.     {
  1190.         playlist_Next( p_playlist );
  1191.     }
  1192.     else if( !strcmp( psz_cmd, "play" ) )
  1193.     {
  1194.         msg_Warn( p_playlist, "play" );
  1195.         playlist_Play( p_playlist );
  1196.     }
  1197.     else if( !strcmp( psz_cmd, "repeat" ) )
  1198.     {
  1199.         bool b_update = true;
  1200.         var_Get( p_playlist, "repeat", &val );
  1201.         if( strlen( newval.psz_string ) > 0 )
  1202.         {
  1203.             if ( ( !strncmp( newval.psz_string, "on", 2 ) && ( val.b_bool == true ) ) ||
  1204.                  ( !strncmp( newval.psz_string, "off", 3 ) && ( val.b_bool == false ) ) )
  1205.             {
  1206.                 b_update = false;
  1207.             }
  1208.         }
  1209.         if ( b_update )
  1210.         {
  1211.             val.b_bool = !val.b_bool;
  1212.             var_Set( p_playlist, "repeat", val );
  1213.         }
  1214.         msg_rc( "Setting repeat to %d", val.b_bool );
  1215.     }
  1216.     else if( !strcmp( psz_cmd, "loop" ) )
  1217.     {
  1218.         bool b_update = true;
  1219.         var_Get( p_playlist, "loop", &val );
  1220.         if( strlen( newval.psz_string ) > 0 )
  1221.         {
  1222.             if ( ( !strncmp( newval.psz_string, "on", 2 ) && ( val.b_bool == true ) ) ||
  1223.                  ( !strncmp( newval.psz_string, "off", 3 ) && ( val.b_bool == false ) ) )
  1224.             {
  1225.                 b_update = false;
  1226.             }
  1227.         }
  1228.         if ( b_update )
  1229.         {
  1230.             val.b_bool = !val.b_bool;
  1231.             var_Set( p_playlist, "loop", val );
  1232.         }
  1233.         msg_rc( "Setting loop to %d", val.b_bool );
  1234.     }
  1235.     else if( !strcmp( psz_cmd, "random" ) )
  1236.     {
  1237.         bool b_update = true;
  1238.         var_Get( p_playlist, "random", &val );
  1239.         if( strlen( newval.psz_string ) > 0 )
  1240.         {
  1241.             if ( ( !strncmp( newval.psz_string, "on", 2 ) && ( val.b_bool == true ) ) ||
  1242.                  ( !strncmp( newval.psz_string, "off", 3 ) && ( val.b_bool == false ) ) )
  1243.             {
  1244.                 b_update = false;
  1245.             }
  1246.         }
  1247.         if ( b_update )
  1248.         {
  1249.             val.b_bool = !val.b_bool;
  1250.             var_Set( p_playlist, "random", val );
  1251.         }
  1252.         msg_rc( "Setting random to %d", val.b_bool );
  1253.     }
  1254.     else if (!strcmp( psz_cmd, "goto" ) )
  1255.     {
  1256.         int i_pos = atoi( newval.psz_string );
  1257.         /* The playlist stores 2 times the same item: onelevel & category */
  1258.         int i_size = p_playlist->items.i_size / 2;
  1259.         if( i_pos <= 0 )
  1260.             msg_rc( "%s", _("Error: `goto' needs an argument greater than zero.") );
  1261.         else if( i_pos <= i_size )
  1262.         {
  1263.             playlist_item_t *p_item, *p_parent;
  1264.             p_item = p_parent = p_playlist->items.p_elems[i_pos*2-1];
  1265.             while( p_parent->p_parent )
  1266.                 p_parent = p_parent->p_parent;
  1267.             playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, pl_Unlocked,
  1268.                     p_parent, p_item );
  1269.         }
  1270.         else
  1271.             msg_rc( _("Playlist has only %d elements"), i_size );
  1272.     }
  1273.     else if( !strcmp( psz_cmd, "stop" ) )
  1274.     {
  1275.         playlist_Stop( p_playlist );
  1276.     }
  1277.     else if( !strcmp( psz_cmd, "clear" ) )
  1278.     {
  1279.         playlist_Stop( p_playlist );
  1280.         playlist_Clear( p_playlist, pl_Unlocked );
  1281.     }
  1282.     else if( !strcmp( psz_cmd, "add" ) &&
  1283.              newval.psz_string && *newval.psz_string )
  1284.     {
  1285.         input_item_t *p_item = parse_MRL( p_intf, newval.psz_string );
  1286.         if( p_item )
  1287.         {
  1288.             msg_rc( "Trying to add %s to playlist.", newval.psz_string );
  1289.             int i_ret =playlist_AddInput( p_playlist, p_item,
  1290.                      PLAYLIST_GO|PLAYLIST_APPEND, PLAYLIST_END, true,
  1291.                      pl_Unlocked );
  1292.             vlc_gc_decref( p_item );
  1293.             if( i_ret != VLC_SUCCESS )
  1294.             {
  1295.                 return VLC_EGENERIC;
  1296.             }
  1297.         }
  1298.     }
  1299.     else if( !strcmp( psz_cmd, "enqueue" ) &&
  1300.              newval.psz_string && *newval.psz_string )
  1301.     {
  1302.         input_item_t *p_item = parse_MRL( p_intf, newval.psz_string );
  1303.         if( p_item )
  1304.         {
  1305.             msg_rc( "trying to enqueue %s to playlist", newval.psz_string );
  1306.             if( playlist_AddInput( p_playlist, p_item,
  1307.                                PLAYLIST_APPEND, PLAYLIST_END, true,
  1308.                                pl_Unlocked ) != VLC_SUCCESS )
  1309.             {
  1310.                 return VLC_EGENERIC;
  1311.             }
  1312.         }
  1313.     }
  1314.     else if( !strcmp( psz_cmd, "playlist" ) )
  1315.     {
  1316.         msg_rc( "+----[ Playlist ]" );
  1317.         print_playlist( p_intf, p_playlist->p_root_category, 0 );
  1318.         msg_rc( "+----[ End of playlist ]" );
  1319.     }
  1320.     else if( !strcmp( psz_cmd, "sort" ))
  1321.     {
  1322.         playlist_RecursiveNodeSort( p_playlist, p_playlist->p_root_onelevel,
  1323.                                     SORT_ARTIST, ORDER_NORMAL );
  1324.     }
  1325.     else if( !strcmp( psz_cmd, "status" ) )
  1326.     {
  1327.         input_thread_t * p_input = playlist_CurrentInput( p_playlist );
  1328.         if( p_input )
  1329.         {
  1330.             /* Replay the current state of the system. */
  1331.             char *psz_uri =
  1332.                     input_item_GetURI( input_GetItem( p_input ) );
  1333.             msg_rc( STATUS_CHANGE "( new input: %s )", psz_uri );
  1334.             free( psz_uri );
  1335.             msg_rc( STATUS_CHANGE "( audio volume: %d )",
  1336.                     config_GetInt( p_intf, "volume" ));
  1337.             PL_LOCK;
  1338.             switch( playlist_Status(p_playlist) )
  1339.             {
  1340.                 case PLAYLIST_STOPPED:
  1341.                     msg_rc( STATUS_CHANGE "( stop state: 5 )" );
  1342.                     break;
  1343.                 case PLAYLIST_RUNNING:
  1344.                     msg_rc( STATUS_CHANGE "( play state: 3 )" );
  1345.                     break;
  1346.                 case PLAYLIST_PAUSED:
  1347.                     msg_rc( STATUS_CHANGE "( pause state: 4 )" );
  1348.                     break;
  1349.                 default:
  1350.                     msg_rc( STATUS_CHANGE "( unknown state: -1 )" );
  1351.                     break;
  1352.             }
  1353.             PL_UNLOCK;
  1354.             vlc_object_release( p_input );
  1355.         }
  1356.     }
  1357.     /*
  1358.      * sanity check
  1359.      */
  1360.     else
  1361.     {
  1362.         msg_rc( "unknown command!" );
  1363.     }
  1364.     pl_Release( p_this );
  1365.     return VLC_SUCCESS;
  1366. }
  1367. static int Quit( vlc_object_t *p_this, char const *psz_cmd,
  1368.                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1369. {
  1370.     VLC_UNUSED(p_data); VLC_UNUSED(psz_cmd);
  1371.     VLC_UNUSED(oldval); VLC_UNUSED(newval);
  1372.     libvlc_Quit( p_this->p_libvlc );
  1373.     return VLC_SUCCESS;
  1374. }
  1375. static int Intf( vlc_object_t *p_this, char const *psz_cmd,
  1376.                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1377. {
  1378.     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
  1379.     intf_thread_t *p_newintf = NULL;
  1380.     p_newintf = intf_Create( p_this->p_libvlc, newval.psz_string );
  1381.     if( p_newintf )
  1382.     {
  1383.         if( intf_RunThread( p_newintf ) )
  1384.         {
  1385.             vlc_object_detach( p_newintf );
  1386.             vlc_object_release( p_newintf );
  1387.         }
  1388.     }
  1389.     return VLC_SUCCESS;
  1390. }
  1391. static int Volume( vlc_object_t *p_this, char const *psz_cmd,
  1392.                    vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1393. {
  1394.     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
  1395.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  1396.     input_thread_t *p_input = NULL;
  1397.     int i_error = VLC_EGENERIC;
  1398.     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
  1399.     if( !p_input )
  1400.         return VLC_ENOOBJ;
  1401.     if( p_input )
  1402.     {
  1403.         vlc_value_t val;
  1404.         var_Get( p_input, "state", &val );
  1405.         if( val.i_int == PAUSE_S )
  1406.         {
  1407.             msg_rc( "%s", _("Type 'menu select' or 'pause' to continue.") );
  1408.             vlc_object_release( p_input );
  1409.             return VLC_EGENERIC;
  1410.         }
  1411.         vlc_object_release( p_input );
  1412.     }
  1413.     if ( *newval.psz_string )
  1414.     {
  1415.         /* Set. */
  1416.         audio_volume_t i_volume = atoi( newval.psz_string );
  1417.         if ( (i_volume > (audio_volume_t)AOUT_VOLUME_MAX) )
  1418.         {
  1419.             msg_rc( "Volume must be in the range %d-%d.", AOUT_VOLUME_MIN,
  1420.                     AOUT_VOLUME_MAX );
  1421.             i_error = VLC_EBADVAR;
  1422.         }
  1423.         else
  1424.         {
  1425.             if( i_volume == AOUT_VOLUME_MIN )
  1426.             {
  1427.                 vlc_value_t keyval;
  1428.                 keyval.i_int = config_GetInt( p_intf, "key-vol-mute" );
  1429.                 var_Set( p_intf->p_libvlc, "key-pressed", keyval );
  1430.             }
  1431.             i_error = aout_VolumeSet( p_this, i_volume );
  1432.             osd_Volume( p_this );
  1433.             msg_rc( STATUS_CHANGE "( audio volume: %d )", i_volume );
  1434.         }
  1435.     }
  1436.     else
  1437.     {
  1438.         /* Get. */
  1439.         audio_volume_t i_volume;
  1440.         if ( aout_VolumeGet( p_this, &i_volume ) < 0 )
  1441.         {
  1442.             i_error = VLC_EGENERIC;
  1443.         }
  1444.         else
  1445.         {
  1446.             msg_rc( STATUS_CHANGE "( audio volume: %d )", i_volume );
  1447.             i_error = VLC_SUCCESS;
  1448.         }
  1449.     }
  1450.     return i_error;
  1451. }
  1452. static int VolumeMove( vlc_object_t *p_this, char const *psz_cmd,
  1453.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1454. {
  1455.     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
  1456.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  1457.     audio_volume_t i_volume;
  1458.     input_thread_t *p_input = NULL;
  1459.     int i_nb_steps = atoi(newval.psz_string);
  1460.     int i_error = VLC_SUCCESS;
  1461.     int i_volume_step = 0;
  1462.     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
  1463.     if( !p_input )
  1464.         return VLC_ENOOBJ;
  1465.     if( p_input )
  1466.     {
  1467.         vlc_value_t val;
  1468.         var_Get( p_input, "state", &val );
  1469.         if( val.i_int == PAUSE_S )
  1470.         {
  1471.             msg_rc( "%s", _("Type 'menu select' or 'pause' to continue.") );
  1472.             vlc_object_release( p_input );
  1473.             return VLC_EGENERIC;
  1474.         }
  1475.         vlc_object_release( p_input );
  1476.     }
  1477.     i_volume_step = config_GetInt( p_intf->p_libvlc, "volume-step" );
  1478.     if ( i_nb_steps <= 0 || i_nb_steps > (AOUT_VOLUME_MAX/i_volume_step) )
  1479.     {
  1480.         i_nb_steps = 1;
  1481.     }
  1482.     if ( !strcmp(psz_cmd, "volup") )
  1483.     {
  1484.         if ( aout_VolumeUp( p_this, i_nb_steps, &i_volume ) < 0 )
  1485.             i_error = VLC_EGENERIC;
  1486.     }
  1487.     else
  1488.     {
  1489.         if ( aout_VolumeDown( p_this, i_nb_steps, &i_volume ) < 0 )
  1490.             i_error = VLC_EGENERIC;
  1491.     }
  1492.     osd_Volume( p_this );
  1493.     if ( !i_error ) msg_rc( STATUS_CHANGE "( audio volume: %d )", i_volume );
  1494.     return i_error;
  1495. }
  1496. static int VideoConfig( vlc_object_t *p_this, char const *psz_cmd,
  1497.                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1498. {
  1499.     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
  1500.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  1501.     input_thread_t *p_input = NULL;
  1502.     vout_thread_t * p_vout;
  1503.     const char * psz_variable = NULL;
  1504.     int i_error;
  1505.     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
  1506.     if( !p_input )
  1507.         return VLC_ENOOBJ;
  1508.     p_vout = vlc_object_find( p_input, VLC_OBJECT_VOUT, FIND_CHILD );
  1509.     vlc_object_release( p_input );
  1510.     if( !p_vout )
  1511.         return VLC_ENOOBJ;
  1512.     if( !strcmp( psz_cmd, "vcrop" ) )
  1513.     {
  1514.         psz_variable = "crop";
  1515.     }
  1516.     else if( !strcmp( psz_cmd, "vratio" ) )
  1517.     {
  1518.         psz_variable = "aspect-ratio";
  1519.     }
  1520.     else if( !strcmp( psz_cmd, "vzoom" ) )
  1521.     {
  1522.         psz_variable = "zoom";
  1523.     }
  1524.     else if( !strcmp( psz_cmd, "snapshot" ) )
  1525.     {
  1526.         psz_variable = "video-snapshot";
  1527.     }
  1528.     else
  1529.         /* This case can't happen */
  1530.         assert( 0 );
  1531.     if( newval.psz_string && *newval.psz_string )
  1532.     {
  1533.         /* set */
  1534.         if( !strcmp( psz_variable, "zoom" ) )
  1535.         {
  1536.             vlc_value_t val;
  1537.             val.f_float = atof( newval.psz_string );
  1538.             i_error = var_Set( p_vout, psz_variable, val );
  1539.         }
  1540.         else
  1541.         {
  1542.             i_error = var_Set( p_vout, psz_variable, newval );
  1543.         }
  1544.     }
  1545.     else if( !strcmp( psz_cmd, "snapshot" ) )
  1546.     {
  1547.         var_TriggerCallback( p_vout, psz_variable );
  1548.     }
  1549.     else
  1550.     {
  1551.         /* get */
  1552.         vlc_value_t val_name;
  1553.         vlc_value_t val, text;
  1554.         int i;
  1555.         float f_value = 0.;
  1556.         char *psz_value = NULL;
  1557.         if ( var_Get( p_vout, psz_variable, &val ) < 0 )
  1558.         {
  1559.             vlc_object_release( p_vout );
  1560.             return VLC_EGENERIC;
  1561.         }
  1562.         if( !strcmp( psz_variable, "zoom" ) )
  1563.         {
  1564.             f_value = val.f_float;
  1565.         }
  1566.         else
  1567.         {
  1568.             psz_value = val.psz_string;
  1569.         }
  1570.         if ( var_Change( p_vout, psz_variable,
  1571.                          VLC_VAR_GETLIST, &val, &text ) < 0 )
  1572.         {
  1573.             vlc_object_release( p_vout );
  1574.             free( psz_value );
  1575.             return VLC_EGENERIC;
  1576.         }
  1577.         /* Get the descriptive name of the variable */
  1578.         var_Change( p_vout, psz_variable, VLC_VAR_GETTEXT,
  1579.                     &val_name, NULL );
  1580.         if( !val_name.psz_string ) val_name.psz_string = strdup(psz_variable);
  1581.         msg_rc( "+----[ %s ]", val_name.psz_string );
  1582.         if( !strcmp( psz_variable, "zoom" ) )
  1583.         {
  1584.             for ( i = 0; i < val.p_list->i_count; i++ )
  1585.             {
  1586.                 if ( f_value == val.p_list->p_values[i].f_float )
  1587.                     msg_rc( "| %f - %s *", val.p_list->p_values[i].f_float,
  1588.                             text.p_list->p_values[i].psz_string );
  1589.                 else
  1590.                     msg_rc( "| %f - %s", val.p_list->p_values[i].f_float,
  1591.                             text.p_list->p_values[i].psz_string );
  1592.             }
  1593.         }
  1594.         else
  1595.         {
  1596.             for ( i = 0; i < val.p_list->i_count; i++ )
  1597.             {
  1598.                 if ( !strcmp( psz_value, val.p_list->p_values[i].psz_string ) )
  1599.                     msg_rc( "| %s - %s *", val.p_list->p_values[i].psz_string,
  1600.                             text.p_list->p_values[i].psz_string );
  1601.                 else
  1602.                     msg_rc( "| %s - %s", val.p_list->p_values[i].psz_string,
  1603.                             text.p_list->p_values[i].psz_string );
  1604.             }
  1605.             free( psz_value );
  1606.         }
  1607.         var_Change( p_vout, psz_variable, VLC_VAR_FREELIST,
  1608.                     &val, &text );
  1609.         msg_rc( "+----[ end of %s ]", val_name.psz_string );
  1610.         free( val_name.psz_string );
  1611.         i_error = VLC_SUCCESS;
  1612.     }
  1613.     vlc_object_release( p_vout );
  1614.     return i_error;
  1615. }
  1616. static int AudioConfig( vlc_object_t *p_this, char const *psz_cmd,
  1617.                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1618. {
  1619.     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
  1620.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  1621.     input_thread_t *p_input = NULL;
  1622.     aout_instance_t * p_aout;
  1623.     const char * psz_variable;
  1624.     vlc_value_t val_name;
  1625.     int i_error;
  1626.     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
  1627.     if( !p_input )
  1628.         return VLC_ENOOBJ;
  1629.     if( p_input )
  1630.     {
  1631.         vlc_value_t val;
  1632.         var_Get( p_input, "state", &val );
  1633.         if( val.i_int == PAUSE_S )
  1634.         {
  1635.             msg_rc( "%s", _("Type 'menu select' or 'pause' to continue.") );
  1636.             vlc_object_release( p_input );
  1637.             return VLC_EGENERIC;
  1638.         }
  1639.         vlc_object_release( p_input );
  1640.     }
  1641.     p_aout = vlc_object_find( p_this, VLC_OBJECT_AOUT, FIND_ANYWHERE );
  1642.     if ( p_aout == NULL ) return VLC_ENOOBJ;
  1643.     if ( !strcmp( psz_cmd, "adev" ) )
  1644.     {
  1645.         psz_variable = "audio-device";
  1646.     }
  1647.     else
  1648.     {
  1649.         psz_variable = "audio-channels";
  1650.     }
  1651.     /* Get the descriptive name of the variable */
  1652.     var_Change( (vlc_object_t *)p_aout, psz_variable, VLC_VAR_GETTEXT,
  1653.                  &val_name, NULL );
  1654.     if( !val_name.psz_string ) val_name.psz_string = strdup(psz_variable);
  1655.     if ( !*newval.psz_string )
  1656.     {
  1657.         /* Retrieve all registered ***. */
  1658.         vlc_value_t val, text;
  1659.         int i, i_value;
  1660.         if ( var_Get( (vlc_object_t *)p_aout, psz_variable, &val ) < 0 )
  1661.         {
  1662.             vlc_object_release( (vlc_object_t *)p_aout );
  1663.             return VLC_EGENERIC;
  1664.         }
  1665.         i_value = val.i_int;
  1666.         if ( var_Change( (vlc_object_t *)p_aout, psz_variable,
  1667.                          VLC_VAR_GETLIST, &val, &text ) < 0 )
  1668.         {
  1669.             vlc_object_release( (vlc_object_t *)p_aout );
  1670.             return VLC_EGENERIC;
  1671.         }
  1672.         msg_rc( "+----[ %s ]", val_name.psz_string );
  1673.         for ( i = 0; i < val.p_list->i_count; i++ )
  1674.         {
  1675.             if ( i_value == val.p_list->p_values[i].i_int )
  1676.                 msg_rc( "| %i - %s *", val.p_list->p_values[i].i_int,
  1677.                         text.p_list->p_values[i].psz_string );
  1678.             else
  1679.                 msg_rc( "| %i - %s", val.p_list->p_values[i].i_int,
  1680.                         text.p_list->p_values[i].psz_string );
  1681.         }
  1682.         var_Change( (vlc_object_t *)p_aout, psz_variable, VLC_VAR_FREELIST,
  1683.                     &val, &text );
  1684.         msg_rc( "+----[ end of %s ]", val_name.psz_string );
  1685.         free( val_name.psz_string );
  1686.         i_error = VLC_SUCCESS;
  1687.     }
  1688.     else
  1689.     {
  1690.         vlc_value_t val;
  1691.         val.i_int = atoi( newval.psz_string );
  1692.         i_error = var_Set( (vlc_object_t *)p_aout, psz_variable, val );
  1693.     }
  1694.     vlc_object_release( (vlc_object_t *)p_aout );
  1695.     return i_error;
  1696. }
  1697. /* OSD menu commands */
  1698. static int Menu( vlc_object_t *p_this, char const *psz_cmd,
  1699.     vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1700. {
  1701.     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
  1702.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  1703.     playlist_t    *p_playlist = NULL;
  1704.     int i_error = VLC_SUCCESS;
  1705.     vlc_value_t val;
  1706.     if ( !*newval.psz_string )
  1707.     {
  1708.         msg_rc( "%s", _("Please provide one of the following parameters:") );
  1709.         msg_rc( "[on|off|up|down|left|right|select]" );
  1710.         return VLC_EGENERIC;
  1711.     }
  1712.     p_playlist = pl_Hold( p_this );
  1713.     input_thread_t * p_input = playlist_CurrentInput( p_playlist );
  1714.     if( p_input )
  1715.     {
  1716.         var_Get( p_input, "state", &val );
  1717.         vlc_object_release( p_input );
  1718.         if( ( val.i_int == PAUSE_S ) &&
  1719.             ( strcmp( newval.psz_string, "select" ) != 0 ) )
  1720.         {
  1721.             msg_rc( "%s", _("Type 'menu select' or 'pause' to continue.") );
  1722.             pl_Release( p_this );
  1723.             return VLC_EGENERIC;
  1724.         }
  1725.     }
  1726.     pl_Release( p_this );
  1727.     val.psz_string = strdup( newval.psz_string );
  1728.     if( !val.psz_string )
  1729.         return VLC_ENOMEM;
  1730.     if( !strcmp( val.psz_string, "on" ) || !strcmp( val.psz_string, "show" ))
  1731.         osd_MenuShow( p_this );
  1732.     else if( !strcmp( val.psz_string, "off" )
  1733.           || !strcmp( val.psz_string, "hide" ) )
  1734.         osd_MenuHide( p_this );
  1735.     else if( !strcmp( val.psz_string, "up" ) )
  1736.         osd_MenuUp( p_this );
  1737.     else if( !strcmp( val.psz_string, "down" ) )
  1738.         osd_MenuDown( p_this );
  1739.     else if( !strcmp( val.psz_string, "left" ) )
  1740.         osd_MenuPrev( p_this );
  1741.     else if( !strcmp( val.psz_string, "right" ) )
  1742.         osd_MenuNext( p_this );
  1743.     else if( !strcmp( val.psz_string, "select" ) )
  1744.         osd_MenuActivate( p_this );
  1745.     else
  1746.     {
  1747.         msg_rc( "%s", _("Please provide one of the following parameters:") );
  1748.         msg_rc( "[on|off|up|down|left|right|select]" );
  1749.         i_error = VLC_EGENERIC;
  1750.     }
  1751.     free( val.psz_string );
  1752.     return i_error;
  1753. }
  1754. static int Statistics ( vlc_object_t *p_this, char const *psz_cmd,
  1755.     vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1756. {
  1757.     VLC_UNUSED(oldval); VLC_UNUSED(newval); VLC_UNUSED(p_data);
  1758.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  1759.     input_thread_t *p_input = NULL;
  1760.     int i_error;
  1761.     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
  1762.     if( !p_input )
  1763.         return VLC_ENOOBJ;
  1764.     if( !strcmp( psz_cmd, "stats" ) )
  1765.     {
  1766.         vlc_mutex_lock( &input_GetItem(p_input)->lock );
  1767.         updateStatistics( p_intf, input_GetItem(p_input) );
  1768.         vlc_mutex_unlock( &input_GetItem(p_input)->lock );
  1769.     }
  1770.     /*
  1771.      * sanity check
  1772.      */
  1773.     else
  1774.     {
  1775.         msg_rc("%s", _("Unknown command!") );
  1776.     }
  1777.     vlc_object_release( p_input );
  1778.     i_error = VLC_SUCCESS;
  1779.     return i_error;
  1780. }
  1781. static int updateStatistics( intf_thread_t *p_intf, input_item_t *p_item )
  1782. {
  1783.     if( !p_item ) return VLC_EGENERIC;
  1784.     vlc_mutex_lock( &p_item->p_stats->lock );
  1785.     msg_rc( "+----[ begin of statistical info ]" );
  1786.     /* Input */
  1787.     msg_rc("%s", _("+-[Incoming]"));
  1788.     msg_rc(_("| input bytes read : %8.0f kB"),
  1789.             (float)(p_item->p_stats->i_read_bytes)/1000 );
  1790.     msg_rc(_("| input bitrate    :   %6.0f kb/s"),
  1791.             (float)(p_item->p_stats->f_input_bitrate)*8000 );
  1792.     msg_rc(_("| demux bytes read : %8.0f kB"),
  1793.             (float)(p_item->p_stats->i_demux_read_bytes)/1000 );
  1794.     msg_rc(_("| demux bitrate    :   %6.0f kb/s"),
  1795.             (float)(p_item->p_stats->f_demux_bitrate)*8000 );
  1796.     msg_rc("|");
  1797.     /* Video */
  1798.     msg_rc("%s", _("+-[Video Decoding]"));
  1799.     msg_rc(_("| video decoded    :    %5i"),
  1800.             p_item->p_stats->i_decoded_video );
  1801.     msg_rc(_("| frames displayed :    %5i"),
  1802.             p_item->p_stats->i_displayed_pictures );
  1803.     msg_rc(_("| frames lost      :    %5i"),
  1804.             p_item->p_stats->i_lost_pictures );
  1805.     msg_rc("|");
  1806.     /* Audio*/
  1807.     msg_rc("%s", _("+-[Audio Decoding]"));
  1808.     msg_rc(_("| audio decoded    :    %5i"),
  1809.             p_item->p_stats->i_decoded_audio );
  1810.     msg_rc(_("| buffers played   :    %5i"),
  1811.             p_item->p_stats->i_played_abuffers );
  1812.     msg_rc(_("| buffers lost     :    %5i"),
  1813.             p_item->p_stats->i_lost_abuffers );
  1814.     msg_rc("|");
  1815.     /* Sout */
  1816.     msg_rc("%s", _("+-[Streaming]"));
  1817.     msg_rc(_("| packets sent     :    %5i"), p_item->p_stats->i_sent_packets );
  1818.     msg_rc(_("| bytes sent       : %8.0f kB"),
  1819.             (float)(p_item->p_stats->i_sent_bytes)/1000 );
  1820.     msg_rc(_("| sending bitrate  :   %6.0f kb/s"),
  1821.             (float)(p_item->p_stats->f_send_bitrate*8)*1000 );
  1822.     msg_rc("|");
  1823.     msg_rc( "+----[ end of statistical info ]" );
  1824.     vlc_mutex_unlock( &p_item->p_stats->lock );
  1825.     return VLC_SUCCESS;
  1826. }
  1827. #ifdef WIN32
  1828. bool ReadWin32( intf_thread_t *p_intf, char *p_buffer, int *pi_size )
  1829. {
  1830.     INPUT_RECORD input_record;
  1831.     DWORD i_dw;
  1832.     /* On Win32, select() only works on socket descriptors */
  1833.     while( WaitForSingleObject( p_intf->p_sys->hConsoleIn,
  1834.                                 INTF_IDLE_SLEEP/1000 ) == WAIT_OBJECT_0 )
  1835.     {
  1836.         while( vlc_object_alive( p_intf ) && *pi_size < MAX_LINE_LENGTH &&
  1837.                ReadConsoleInput( p_intf->p_sys->hConsoleIn, &input_record,
  1838.                                  1, &i_dw ) )
  1839.         {
  1840.             if( input_record.EventType != KEY_EVENT ||
  1841.                 !input_record.Event.KeyEvent.bKeyDown ||
  1842.                 input_record.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT ||
  1843.                 input_record.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL||
  1844.                 input_record.Event.KeyEvent.wVirtualKeyCode == VK_MENU ||
  1845.                 input_record.Event.KeyEvent.wVirtualKeyCode == VK_CAPITAL )
  1846.             {
  1847.                 /* nothing interesting */
  1848.                 continue;
  1849.             }
  1850.             p_buffer[ *pi_size ] = input_record.Event.KeyEvent.uChar.AsciiChar;
  1851.             /* Echo out the command */
  1852.             putc( p_buffer[ *pi_size ], stdout );
  1853.             /* Handle special keys */
  1854.             if( p_buffer[ *pi_size ] == 'r' || p_buffer[ *pi_size ] == 'n' )
  1855.             {
  1856.                 putc( 'n', stdout );
  1857.                 break;
  1858.             }
  1859.             switch( p_buffer[ *pi_size ] )
  1860.             {
  1861.             case 'b':
  1862.                 if( *pi_size )
  1863.                 {
  1864.                     *pi_size -= 2;
  1865.                     putc( ' ', stdout );
  1866.                     putc( 'b', stdout );
  1867.                 }
  1868.                 break;
  1869.             case 'r':
  1870.                 (*pi_size) --;
  1871.                 break;
  1872.             }
  1873.             (*pi_size)++;
  1874.         }
  1875.         if( *pi_size == MAX_LINE_LENGTH ||
  1876.             p_buffer[ *pi_size ] == 'r' || p_buffer[ *pi_size ] == 'n' )
  1877.         {
  1878.             p_buffer[ *pi_size ] = 0;
  1879.             return true;
  1880.         }
  1881.     }
  1882.     return false;
  1883. }
  1884. #endif
  1885. bool ReadCommand( intf_thread_t *p_intf, char *p_buffer, int *pi_size )
  1886. {
  1887.     int i_read = 0;
  1888. #ifdef WIN32
  1889.     if( p_intf->p_sys->i_socket == -1 && !p_intf->p_sys->b_quiet )
  1890.         return ReadWin32( p_intf, p_buffer, pi_size );
  1891.     else if( p_intf->p_sys->i_socket == -1 )
  1892.     {
  1893.         msleep( INTF_IDLE_SLEEP );
  1894.         return false;
  1895.     }
  1896. #endif
  1897.     while( vlc_object_alive( p_intf ) && *pi_size < MAX_LINE_LENGTH &&
  1898.            (i_read = net_Read( p_intf, p_intf->p_sys->i_socket == -1 ?
  1899.                        0 /*STDIN_FILENO*/ : p_intf->p_sys->i_socket, NULL,
  1900.                   (uint8_t *)p_buffer + *pi_size, 1, false ) ) > 0 )
  1901.     {
  1902.         if( p_buffer[ *pi_size ] == 'r' || p_buffer[ *pi_size ] == 'n' )
  1903.             break;
  1904.         (*pi_size)++;
  1905.     }
  1906.     /* Connection closed */
  1907.     if( i_read <= 0 )
  1908.     {
  1909.         if( p_intf->p_sys->i_socket != -1 )
  1910.         {
  1911.             net_Close( p_intf->p_sys->i_socket );
  1912.             p_intf->p_sys->i_socket = -1;
  1913.         }
  1914.         else
  1915.         {
  1916.             /* Standard input closed: exit */
  1917.             vlc_value_t empty;
  1918.             Quit( VLC_OBJECT(p_intf), NULL, empty, empty, NULL );
  1919.         }
  1920.         p_buffer[ *pi_size ] = 0;
  1921.         return true;
  1922.     }
  1923.     if( *pi_size == MAX_LINE_LENGTH ||
  1924.         p_buffer[ *pi_size ] == 'r' || p_buffer[ *pi_size ] == 'n' )
  1925.     {
  1926.         p_buffer[ *pi_size ] = 0;
  1927.         return true;
  1928.     }
  1929.     return false;
  1930. }
  1931. /*****************************************************************************
  1932.  * parse_MRL: build a input item from a full mrl
  1933.  *****************************************************************************
  1934.  * MRL format: "simplified-mrl [:option-name[=option-value]]"
  1935.  * We don't check for '"' or ''', we just assume that a ':' that follows a
  1936.  * space is a new option. Should be good enough for our purpose.
  1937.  *****************************************************************************/
  1938. static input_item_t *parse_MRL( intf_thread_t *p_intf, char *psz_mrl )
  1939. {
  1940. #define SKIPSPACE( p ) { while( *p == ' ' || *p == 't' ) p++; }
  1941. #define SKIPTRAILINGSPACE( p, d ) 
  1942.     { char *e=d; while( e > p && (*(e-1)==' ' || *(e-1)=='t') ){e--;*e=0;} }
  1943.     input_item_t *p_item = NULL;
  1944.     char *psz_item = NULL, *psz_item_mrl = NULL, *psz_orig;
  1945.     char **ppsz_options = NULL;
  1946.     int i, i_options = 0;
  1947.     if( !psz_mrl ) return 0;
  1948.     psz_mrl = psz_orig = strdup( psz_mrl );
  1949.     while( *psz_mrl )
  1950.     {
  1951.         SKIPSPACE( psz_mrl );
  1952.         psz_item = psz_mrl;
  1953.         for( ; *psz_mrl; psz_mrl++ )
  1954.         {
  1955.             if( (*psz_mrl == ' ' || *psz_mrl == 't') && psz_mrl[1] == ':' )
  1956.             {
  1957.                 /* We have a complete item */
  1958.                 break;
  1959.             }
  1960.             if( (*psz_mrl == ' ' || *psz_mrl == 't') &&
  1961.                 (psz_mrl[1] == '"' || psz_mrl[1] == ''') && psz_mrl[2] == ':')
  1962.             {
  1963.                 /* We have a complete item */
  1964.                 break;
  1965.             }
  1966.         }
  1967.         if( *psz_mrl ) { *psz_mrl = 0; psz_mrl++; }
  1968.         SKIPTRAILINGSPACE( psz_item, psz_item + strlen( psz_item ) );
  1969.         /* Remove '"' and ''' if necessary */
  1970.         if( *psz_item == '"' && psz_item[strlen(psz_item)-1] == '"' )
  1971.         { psz_item++; psz_item[strlen(psz_item)-1] = 0; }
  1972.         if( *psz_item == ''' && psz_item[strlen(psz_item)-1] == ''' )
  1973.         { psz_item++; psz_item[strlen(psz_item)-1] = 0; }
  1974.         if( !psz_item_mrl ) psz_item_mrl = psz_item;
  1975.         else if( *psz_item )
  1976.         {
  1977.             i_options++;
  1978.             ppsz_options = realloc( ppsz_options, i_options * sizeof(char *) );
  1979.             ppsz_options[i_options - 1] = &psz_item[1];
  1980.         }
  1981.         if( *psz_mrl ) SKIPSPACE( psz_mrl );
  1982.     }
  1983.     /* Now create a playlist item */
  1984.     if( psz_item_mrl )
  1985.     {
  1986.         p_item = input_item_New( p_intf, psz_item_mrl, NULL );
  1987.         for( i = 0; i < i_options; i++ )
  1988.         {
  1989.             input_item_AddOption( p_item, ppsz_options[i], VLC_INPUT_OPTION_TRUSTED );
  1990.         }
  1991.     }
  1992.     if( i_options ) free( ppsz_options );
  1993.     free( psz_orig );
  1994.     return p_item;
  1995. }