]> git.sesse.net Git - vlc/blobdiff - modules/control/rc.c
Simple: fix memleak on quit
[vlc] / modules / control / rc.c
index 7f71dcb4614ab034b901dcb5317b84370be817dc..d51ddc9840d3b1ba92c8c822337439813fa54c8d 100644 (file)
@@ -41,7 +41,6 @@
 #include <vlc_interface.h>
 #include <vlc_aout.h>
 #include <vlc_vout.h>
-#include <vlc_osd.h>
 #include <vlc_playlist.h>
 #include <vlc_keys.h>
 
@@ -108,8 +107,6 @@ static int  AudioDevice  ( vlc_object_t *, char const *,
                            vlc_value_t, vlc_value_t, void * );
 static int  AudioChannel ( vlc_object_t *, char const *,
                            vlc_value_t, vlc_value_t, void * );
-static int  Menu         ( vlc_object_t *, char const *,
-                           vlc_value_t, vlc_value_t, void * );
 static int  Statistics   ( vlc_object_t *, char const *,
                            vlc_value_t, vlc_value_t, void * );
 
@@ -132,6 +129,7 @@ struct intf_sys_t
     vlc_mutex_t       status_lock;
     int               i_last_state;
     playlist_t        *p_playlist;
+    input_thread_t    *p_input;
     bool              b_input_buffering;
 
 #ifdef WIN32
@@ -216,6 +214,7 @@ static int Activate( vlc_object_t *p_this )
 {
     /* FIXME: This function is full of memory leaks and bugs in error paths. */
     intf_thread_t *p_intf = (intf_thread_t*)p_this;
+    playlist_t *p_playlist = pl_Get( p_intf );
     char *psz_host, *psz_unix_path = NULL;
     int  *pi_socket = NULL;
 
@@ -319,33 +318,38 @@ static int Activate( vlc_object_t *p_this )
         free( psz_host );
     }
 
-    p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
-    if( !p_intf->p_sys )
+    intf_sys_t *p_sys = malloc( sizeof( *p_sys ) );
+    if( unlikely(p_sys == NULL) )
         return VLC_ENOMEM;
 
-    p_intf->p_sys->pi_socket_listen = pi_socket;
-    p_intf->p_sys->i_socket = -1;
-    p_intf->p_sys->psz_unix_path = psz_unix_path;
-    vlc_mutex_init( &p_intf->p_sys->status_lock );
-    p_intf->p_sys->i_last_state = PLAYLIST_STOPPED;
-    p_intf->p_sys->b_input_buffering = false;
+    p_intf->p_sys = p_sys;
+    p_sys->pi_socket_listen = pi_socket;
+    p_sys->i_socket = -1;
+    p_sys->psz_unix_path = psz_unix_path;
+    vlc_mutex_init( &p_sys->status_lock );
+    p_sys->i_last_state = PLAYLIST_STOPPED;
+    p_sys->b_input_buffering = false;
+    p_sys->p_playlist = p_playlist;
+    p_sys->p_input = NULL;
 
     /* Non-buffered stdout */
     setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
 
 #ifdef WIN32
-    p_intf->p_sys->b_quiet = var_InheritBool( p_intf, "rc-quiet" );
-    if( !p_intf->p_sys->b_quiet )
+    p_sys->b_quiet = var_InheritBool( p_intf, "rc-quiet" );
+    if( !p_sys->b_quiet )
 #endif
     {
         CONSOLE_INTRO_MSG;
     }
 
-    if( vlc_clone( &p_intf->p_sys->thread, Run, p_intf,
-                   VLC_THREAD_PRIORITY_LOW ) )
+    if( vlc_clone( &p_sys->thread, Run, p_intf, VLC_THREAD_PRIORITY_LOW ) )
         abort();
 
     msg_rc( "%s", _("Remote control interface initialized. Type `help' for help.") );
+
+    /* Listen to audio volume updates */
+    var_AddCallback( p_sys->p_playlist, "volume", VolumeChanged, p_intf );
     return VLC_SUCCESS;
 }
 
@@ -355,21 +359,30 @@ static int Activate( vlc_object_t *p_this )
 static void Deactivate( vlc_object_t *p_this )
 {
     intf_thread_t *p_intf = (intf_thread_t*)p_this;
+    intf_sys_t *p_sys = p_intf->p_sys;
 
-    vlc_join( p_intf->p_sys->thread, NULL );
+    vlc_cancel( p_sys->thread );
+    var_DelCallback( p_sys->p_playlist, "volume", VolumeChanged, p_intf );
+    vlc_join( p_sys->thread, NULL );
 
-    net_ListenClose( p_intf->p_sys->pi_socket_listen );
-    if( p_intf->p_sys->i_socket != -1 )
-        net_Close( p_intf->p_sys->i_socket );
-    if( p_intf->p_sys->psz_unix_path != NULL )
+    if( p_sys->p_input != NULL )
+    {
+        var_DelCallback( p_sys->p_input, "intf-event", InputEvent, p_intf );
+        vlc_object_release( p_sys->p_input );
+    }
+
+    net_ListenClose( p_sys->pi_socket_listen );
+    if( p_sys->i_socket != -1 )
+        net_Close( p_sys->i_socket );
+    if( p_sys->psz_unix_path != NULL )
     {
 #if defined(AF_LOCAL) && !defined(WIN32)
-        unlink( p_intf->p_sys->psz_unix_path );
+        unlink( p_sys->psz_unix_path );
 #endif
-        free( p_intf->p_sys->psz_unix_path );
+        free( p_sys->psz_unix_path );
     }
-    vlc_mutex_destroy( &p_intf->p_sys->status_lock );
-    free( p_intf->p_sys );
+    vlc_mutex_destroy( &p_sys->status_lock );
+    free( p_sys );
 }
 
 /*****************************************************************************
@@ -399,9 +412,6 @@ static void RegisterCallbacks( intf_thread_t *p_intf )
     ADD( "goto", INTEGER, Playlist )
     ADD( "status", INTEGER, Playlist )
 
-    /* OSD menu commands */
-    ADD(  "menu", STRING, Menu )
-
     /* DVD commands */
     ADD( "pause", VOID, Input )
     ADD( "seek", INTEGER, Input )
@@ -451,8 +461,7 @@ static void RegisterCallbacks( intf_thread_t *p_intf )
 static void *Run( void *data )
 {
     intf_thread_t *p_intf = data;
-    input_thread_t * p_input = NULL;
-    playlist_t *     p_playlist = pl_Get( p_intf );
+    intf_sys_t *p_sys = p_intf->p_sys;
 
     char p_buffer[ MAX_LINE_LENGTH + 1 ];
     bool b_showpos = var_InheritBool( p_intf, "rc-show-pos" );
@@ -461,6 +470,7 @@ static void *Run( void *data )
     int  i_size = 0;
     int  i_oldpos = 0;
     int  i_newpos;
+    int  canc = vlc_savecancel( );
 
     p_buffer[0] = 0;
 
@@ -475,88 +485,83 @@ static void *Run( void *data )
 #endif
 
     /* Register commands that will be cleaned up upon object destruction */
-    p_intf->p_sys->p_playlist = p_playlist;
     RegisterCallbacks( p_intf );
 
     /* status callbacks */
-    /* Listen to audio volume updates */
-    var_AddCallback( p_playlist, "volume", VolumeChanged, p_intf );
 
-    while( vlc_object_alive( p_intf ) )
+    for( ;; )
     {
         char *psz_cmd, *psz_arg;
         bool b_complete;
 
-        if( p_intf->p_sys->pi_socket_listen != NULL &&
-            p_intf->p_sys->i_socket == -1 )
+        vlc_restorecancel( canc );
+
+        if( p_sys->pi_socket_listen != NULL && p_sys->i_socket == -1 )
         {
-            p_intf->p_sys->i_socket =
-                net_Accept( p_intf, p_intf->p_sys->pi_socket_listen );
-            if( p_intf->p_sys->i_socket == -1 ) continue;
+            p_sys->i_socket =
+                net_Accept( p_intf, p_sys->pi_socket_listen );
+            if( p_sys->i_socket == -1 ) continue;
         }
 
         b_complete = ReadCommand( p_intf, p_buffer, &i_size );
+        canc = vlc_savecancel( );
 
         /* Manage the input part */
-        if( p_input == NULL )
+        if( p_sys->p_input == NULL )
         {
-            p_input = playlist_CurrentInput( p_playlist );
+            p_sys->p_input = playlist_CurrentInput( p_sys->p_playlist );
             /* New input has been registered */
-            if( p_input )
+            if( p_sys->p_input )
             {
-                if( !p_input->b_dead || vlc_object_alive (p_input) )
-                {
-                    char *psz_uri =
-                            input_item_GetURI( input_GetItem( p_input ) );
-                    msg_rc( STATUS_CHANGE "( new input: %s )", psz_uri );
-                    free( psz_uri );
-                }
-                var_AddCallback( p_input, "intf-event", InputEvent, p_intf );
+                char *psz_uri = input_item_GetURI( input_GetItem( p_sys->p_input ) );
+                msg_rc( STATUS_CHANGE "( new input: %s )", psz_uri );
+                free( psz_uri );
+
+                var_AddCallback( p_sys->p_input, "intf-event", InputEvent, p_intf );
             }
         }
-        else if( p_input->b_dead )
+#warning This is not reliable...
+        else if( p_sys->p_input->b_dead )
         {
-            var_DelCallback( p_input, "intf-event", InputEvent, p_intf );
-            vlc_object_release( p_input );
-            p_input = NULL;
+            var_DelCallback( p_sys->p_input, "intf-event", InputEvent, p_intf );
+            vlc_object_release( p_sys->p_input );
+            p_sys->p_input = NULL;
 
-            if( p_playlist )
-            {
-                p_intf->p_sys->i_last_state = PLAYLIST_STOPPED;
-                msg_rc( STATUS_CHANGE "( stop state: 0 )" );
-            }
+            p_sys->i_last_state = PLAYLIST_STOPPED;
+            msg_rc( STATUS_CHANGE "( stop state: 0 )" );
         }
 
-        if( (p_input != NULL) && !p_input->b_dead && vlc_object_alive (p_input) &&
-            (p_playlist != NULL) )
+        if( p_sys->p_input != NULL )
         {
+            playlist_t *p_playlist = p_sys->p_playlist;
+
             PL_LOCK;
             int status = playlist_Status( p_playlist );
             PL_UNLOCK;
 
-            if( p_intf->p_sys->i_last_state != status )
+            if( p_sys->i_last_state != status )
             {
                 if( status == PLAYLIST_STOPPED )
                 {
-                    p_intf->p_sys->i_last_state = PLAYLIST_STOPPED;
+                    p_sys->i_last_state = PLAYLIST_STOPPED;
                     msg_rc( STATUS_CHANGE "( stop state: 5 )" );
                 }
                 else if( status == PLAYLIST_RUNNING )
                 {
-                    p_intf->p_sys->i_last_state = PLAYLIST_RUNNING;
+                    p_sys->i_last_state = PLAYLIST_RUNNING;
                     msg_rc( STATUS_CHANGE "( play state: 3 )" );
                 }
                 else if( status == PLAYLIST_PAUSED )
                 {
-                    p_intf->p_sys->i_last_state = PLAYLIST_PAUSED;
+                    p_sys->i_last_state = PLAYLIST_PAUSED;
                     msg_rc( STATUS_CHANGE "( pause state: 4 )" );
                 }
             }
         }
 
-        if( p_input && b_showpos )
+        if( p_sys->p_input && b_showpos )
         {
-            i_newpos = 100 * var_GetFloat( p_input, "position" );
+            i_newpos = 100 * var_GetFloat( p_sys->p_input, "position" );
             if( i_oldpos != i_newpos )
             {
                 i_oldpos = i_newpos;
@@ -624,9 +629,12 @@ static void *Run( void *data )
         {
             vlc_value_t val;
             int i_ret;
-
             val.psz_string = psz_arg;
-            i_ret = var_Set( p_intf, psz_cmd, val );
+
+            if ((var_Type( p_intf, psz_cmd) & VLC_VAR_CLASS) == VLC_VAR_VOID)
+                i_ret = var_TriggerCallback( p_intf, psz_cmd );
+            else
+                i_ret = var_Set( p_intf, psz_cmd, val );
             msg_rc( "%s: returned %i (%s)",
                     psz_cmd, i_ret, vlc_error( i_ret ) );
         }
@@ -639,7 +647,10 @@ static void *Run( void *data )
             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 );
+            if ((var_Type( p_intf->p_libvlc, psz_cmd) & VLC_VAR_CLASS) == VLC_VAR_VOID)
+                i_ret = var_TriggerCallback( p_intf, psz_cmd );
+            else
+                i_ret = var_Set( p_intf->p_libvlc, psz_cmd, val );
             if( i_ret != 0 )
             {
                 msg_rc( "%s: returned %i (%s)",
@@ -649,21 +660,21 @@ static void *Run( void *data )
         else if( !strcmp( psz_cmd, "logout" ) )
         {
             /* Close connection */
-            if( p_intf->p_sys->i_socket != -1 )
+            if( p_sys->i_socket != -1 )
             {
-                net_Close( p_intf->p_sys->i_socket );
+                net_Close( p_sys->i_socket );
+                p_sys->i_socket = -1;
             }
-            p_intf->p_sys->i_socket = -1;
         }
         else if( !strcmp( psz_cmd, "info" ) )
         {
-            if( p_input )
+            if( p_sys->p_input )
             {
                 int i, j;
-                vlc_mutex_lock( &input_GetItem(p_input)->lock );
-                for ( i = 0; i < input_GetItem(p_input)->i_categories; i++ )
+                vlc_mutex_lock( &input_GetItem(p_sys->p_input)->lock );
+                for ( i = 0; i < input_GetItem(p_sys->p_input)->i_categories; i++ )
                 {
-                    info_category_t *p_category = input_GetItem(p_input)
+                    info_category_t *p_category = input_GetItem(p_sys->p_input)
                                                         ->pp_categories[i];
 
                     msg_rc( "+----[ %s ]", p_category->psz_name );
@@ -677,7 +688,7 @@ static void *Run( void *data )
                     msg_rc( "| " );
                 }
                 msg_rc( "+----[ end of stream info ]" );
-                vlc_mutex_unlock( &input_GetItem(p_input)->lock );
+                vlc_mutex_unlock( &input_GetItem(p_sys->p_input)->lock );
             }
             else
             {
@@ -686,7 +697,7 @@ static void *Run( void *data )
         }
         else if( !strcmp( psz_cmd, "is_playing" ) )
         {
-            if( ! p_input )
+            if( p_sys->p_input == NULL )
             {
                 msg_rc( "0" );
             }
@@ -697,39 +708,39 @@ static void *Run( void *data )
         }
         else if( !strcmp( psz_cmd, "get_time" ) )
         {
-            if( ! p_input )
+            if( p_sys->p_input == NULL )
             {
                 msg_rc("0");
             }
             else
             {
                 vlc_value_t time;
-                var_Get( p_input, "time", &time );
+                var_Get( p_sys->p_input, "time", &time );
                 msg_rc( "%"PRIu64, time.i_time / 1000000);
             }
         }
         else if( !strcmp( psz_cmd, "get_length" ) )
         {
-            if( ! p_input )
+            if( p_sys->p_input == NULL )
             {
                 msg_rc("0");
             }
             else
             {
                 vlc_value_t time;
-                var_Get( p_input, "length", &time );
+                var_Get( p_sys->p_input, "length", &time );
                 msg_rc( "%"PRIu64, time.i_time / 1000000);
             }
         }
         else if( !strcmp( psz_cmd, "get_title" ) )
         {
-            if( ! p_input )
+            if( p_sys->p_input == NULL )
             {
                 msg_rc("%s", "");
             }
             else
             {
-                msg_rc( "%s", input_GetItem(p_input)->psz_name );
+                msg_rc( "%s", input_GetItem(p_sys->p_input)->psz_name );
             }
         }
         else if( !strcmp( psz_cmd, "longhelp" ) || !strncmp( psz_cmd, "h", 1 )
@@ -754,15 +765,15 @@ static void *Run( void *data )
             bool fs;
 
             if( !strncasecmp( psz_arg, "on", 2 ) )
-                var_SetBool( p_playlist, "fullscreen", fs = true );
+                var_SetBool( p_sys->p_playlist, "fullscreen", fs = true );
             else if( !strncasecmp( psz_arg, "off", 3 ) )
-                var_SetBool( p_playlist, "fullscreen", fs = false );
+                var_SetBool( p_sys->p_playlist, "fullscreen", fs = false );
             else
-                fs = var_ToggleBool( p_playlist, "fullscreen" );
+                fs = var_ToggleBool( p_sys->p_playlist, "fullscreen" );
 
-            if( p_input )
+            if( p_sys->p_input == NULL )
             {
-                vout_thread_t *p_vout = input_GetVout( p_input );
+                vout_thread_t *p_vout = input_GetVout( p_sys->p_input );
                 if( p_vout )
                 {
                     var_SetBool( p_vout, "fullscreen", fs );
@@ -792,13 +803,8 @@ static void *Run( void *data )
     msg_rc( STATUS_CHANGE "( stop state: 0 )" );
     msg_rc( STATUS_CHANGE "( quit )" );
 
-    if( p_input )
-    {
-        var_DelCallback( p_input, "intf-event", InputEvent, p_intf );
-        vlc_object_release( p_input );
-    }
+    vlc_restorecancel( canc );
 
-    var_DelCallback( p_playlist, "volume", VolumeChanged, p_intf );
     return NULL;
 }
 
@@ -853,7 +859,7 @@ static void Help( intf_thread_t *p_intf, bool b_longhelp)
     msg_rc("%s", _("| vcrop [X]  . . . . . . . . . . .  set/get video crop"));
     msg_rc("%s", _("| vzoom [X]  . . . . . . . . . . .  set/get video zoom"));
     msg_rc("%s", _("| snapshot . . . . . . . . . . . . take video snapshot"));
-    msg_rc("%s", _("| strack [X] . . . . . . . . . set/get subtitles track"));
+    msg_rc("%s", _("| strack [X] . . . . . . . . .  set/get subtitle track"));
     msg_rc("%s", _("| key [hotkey name] . . . . . .  simulate hotkey press"));
     msg_rc("%s", _("| menu . . [on|off|up|down|left|right|select] use menu"));
     msg_rc(  "| ");
@@ -1778,67 +1784,6 @@ out:
     return ret;
 }
 
-/* OSD menu commands */
-static int Menu( vlc_object_t *p_this, char const *psz_cmd,
-    vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
-    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
-    intf_thread_t *p_intf = (intf_thread_t*)p_this;
-    playlist_t    *p_playlist = p_intf->p_sys->p_playlist;
-    int i_error = VLC_SUCCESS;
-    vlc_value_t val;
-
-    if ( !*newval.psz_string )
-    {
-        msg_rc( "%s", _("Please provide one of the following parameters:") );
-        msg_rc( "[on|off|up|down|left|right|select]" );
-        return VLC_EGENERIC;
-    }
-
-    input_thread_t * p_input = playlist_CurrentInput( p_playlist );
-
-    if( p_input )
-    {
-        var_Get( p_input, "state", &val );
-        vlc_object_release( p_input );
-
-        if( ( val.i_int == PAUSE_S ) &&
-            ( strcmp( newval.psz_string, "select" ) != 0 ) )
-        {
-            msg_rc( "%s", _("Type 'menu select' or 'pause' to continue.") );
-            return VLC_EGENERIC;
-        }
-    }
-
-    val.psz_string = strdup( newval.psz_string );
-    if( !val.psz_string )
-        return VLC_ENOMEM;
-    if( !strcmp( val.psz_string, "on" ) || !strcmp( val.psz_string, "show" ))
-        osd_MenuShow( p_this );
-    else if( !strcmp( val.psz_string, "off" )
-          || !strcmp( val.psz_string, "hide" ) )
-        osd_MenuHide( p_this );
-    else if( !strcmp( val.psz_string, "up" ) )
-        osd_MenuUp( p_this );
-    else if( !strcmp( val.psz_string, "down" ) )
-        osd_MenuDown( p_this );
-    else if( !strcmp( val.psz_string, "left" ) )
-        osd_MenuPrev( p_this );
-    else if( !strcmp( val.psz_string, "right" ) )
-        osd_MenuNext( p_this );
-    else if( !strcmp( val.psz_string, "select" ) )
-        osd_MenuActivate( p_this );
-    else
-    {
-        msg_rc( "%s", _("Please provide one of the following parameters:") );
-        msg_rc( "[on|off|up|down|left|right|select]" );
-        i_error = VLC_EGENERIC;
-    }
-
-    free( val.psz_string );
-    return i_error;
-}
-
 static int Statistics ( vlc_object_t *p_this, char const *psz_cmd,
     vlc_value_t oldval, vlc_value_t newval, void *p_data )
 {
@@ -1922,7 +1867,7 @@ static bool ReadWin32( intf_thread_t *p_intf, char *p_buffer, int *pi_size )
     while( WaitForSingleObject( p_intf->p_sys->hConsoleIn,
                                 INTF_IDLE_SLEEP/1000 ) == WAIT_OBJECT_0 )
     {
-        while( vlc_object_alive( p_intf ) && *pi_size < MAX_LINE_LENGTH &&
+        while( *pi_size < MAX_LINE_LENGTH &&
                ReadConsoleInput( p_intf->p_sys->hConsoleIn, &input_record,
                                  1, &i_dw ) )
         {
@@ -1992,7 +1937,7 @@ bool ReadCommand( intf_thread_t *p_intf, char *p_buffer, int *pi_size )
     }
 #endif
 
-    while( vlc_object_alive( p_intf ) && *pi_size < MAX_LINE_LENGTH &&
+    while( *pi_size < MAX_LINE_LENGTH &&
            (i_read = net_Read( p_intf, p_intf->p_sys->i_socket == -1 ?
                        0 /*STDIN_FILENO*/ : p_intf->p_sys->i_socket, NULL,
                   (uint8_t *)p_buffer + *pi_size, 1, false ) ) > 0 )