hotkeys: listen to new inputs and new vouts
authorThomas Guillem <thomas@gllm.fr>
Wed, 16 Nov 2016 18:30:27 +0000 (19:30 +0100)
committerThomas Guillem <thomas@gllm.fr>
Fri, 18 Nov 2016 09:45:39 +0000 (10:45 +0100)
Listen to playlist "input-current" to update the current input_thead_t, and
listen to input "intf-event" to update the current vout. The vout/input don't
need to be fetched when processing an action, this removes one FIXME, but this
adds more lock complexity.

This will be mainly needed for the next commit, in order to listen to mouse
events from the vout.

modules/control/hotkeys.c

index 40b9672..675ec67 100644 (file)
 #include <vlc_keys.h>
 #include "math.h"
 
+#include <assert.h>
+
 /*****************************************************************************
  * intf_sys_t: description and status of FB interface
  *****************************************************************************/
 struct intf_sys_t
 {
-    vout_thread_t      *p_last_vout;
+    vlc_mutex_t         lock;
+    vout_thread_t      *p_vout;
+    input_thread_t     *p_input;
     int slider_chan;
 
     /*subtitle_delaybookmarks: placeholder for storing subtitle sync timestamps*/
@@ -67,11 +71,11 @@ static int  ActionEvent( vlc_object_t *, char const *,
                          vlc_value_t, vlc_value_t, void * );
 static void PlayBookmark( intf_thread_t *, int );
 static void SetBookmark ( intf_thread_t *, int );
-static void DisplayPosition( intf_thread_t *, vout_thread_t *, input_thread_t * );
-static void DisplayVolume( intf_thread_t *, vout_thread_t *, float );
+static void DisplayPosition( vout_thread_t *, int,  input_thread_t * );
+static void DisplayVolume( vout_thread_t *, int, float );
 static void DisplayRate ( vout_thread_t *, float );
 static float AdjustRateFine( vlc_object_t *, const int );
-static void ClearChannels  ( intf_thread_t *, vout_thread_t * );
+static void ClearChannels  ( vout_thread_t *, int );
 
 #define DisplayMessage(vout, ...) \
     do { \
@@ -95,6 +99,83 @@ vlc_module_begin ()
 
 vlc_module_end ()
 
+static void ChangeVout( intf_thread_t *p_intf, vout_thread_t *p_vout )
+{
+    intf_sys_t *p_sys = p_intf->p_sys;
+
+    int slider_chan;
+    if( p_vout != NULL )
+        slider_chan = vout_RegisterSubpictureChannel( p_vout );
+
+    vlc_mutex_lock( &p_sys->lock );
+    vout_thread_t *p_old_vout = p_sys->p_vout;
+    p_sys->p_vout = p_vout;
+    if( p_vout != NULL )
+        p_sys->slider_chan = slider_chan;
+    vlc_mutex_unlock( &p_sys->lock );
+
+    if( p_old_vout != NULL )
+        vlc_object_release( p_old_vout );
+}
+
+static int InputEvent( vlc_object_t *p_this, char const *psz_var,
+                       vlc_value_t oldval, vlc_value_t val, void *p_data )
+{
+    input_thread_t *p_input = (input_thread_t *)p_this;
+    intf_thread_t *p_intf = p_data;
+
+    (void) psz_var; (void) oldval;
+
+    if( val.i_int == INPUT_EVENT_VOUT )
+        ChangeVout( p_intf, input_GetVout( p_input ) );
+
+    return VLC_SUCCESS;
+}
+
+static void ChangeInput( intf_thread_t *p_intf, input_thread_t *p_input )
+{
+    intf_sys_t *p_sys = p_intf->p_sys;
+
+    input_thread_t *p_old_input = p_sys->p_input;
+    if( p_old_input != NULL )
+    {
+        /* First, remove callbacks from previous input. It's safe to access it
+         * unlocked, since it's written from this thread */
+        var_DelCallback( p_old_input, "intf-event", InputEvent, p_intf );
+    }
+
+    /* Replace input and vout locked */
+    vlc_mutex_lock( &p_sys->lock );
+    vout_thread_t *p_old_vout = p_sys->p_vout;
+    p_sys->p_input = p_input ? vlc_object_hold( p_input ) : NULL;
+    p_sys->p_vout = NULL;
+    vlc_mutex_unlock( &p_sys->lock );
+
+    /* Release old input and vout objects unlocked */
+    if( p_old_input != NULL )
+    {
+        if( p_old_vout != NULL )
+            vlc_object_release( p_old_vout );
+        vlc_object_release( p_old_input );
+    }
+
+    /* Register input events */
+    if( p_input != NULL )
+        var_AddCallback( p_input, "intf-event", InputEvent, p_intf );
+}
+
+static int PlaylistEvent( vlc_object_t *p_this, char const *psz_var,
+                          vlc_value_t oldval, vlc_value_t val, void *p_data )
+{
+    intf_thread_t *p_intf = p_data;
+
+    (void) p_this; (void) psz_var; (void) oldval;
+
+    ChangeInput( p_intf, val.p_address );
+
+    return VLC_SUCCESS;
+}
+
 /*****************************************************************************
  * Open: initialize interface
  *****************************************************************************/
@@ -108,11 +189,17 @@ static int Open( vlc_object_t *p_this )
 
     p_intf->p_sys = p_sys;
 
-    p_sys->p_last_vout = NULL;
+    p_sys->p_vout = NULL;
+    p_sys->p_input = NULL;
     p_sys->subtitle_delaybookmarks.i_time_audio = 0;
     p_sys->subtitle_delaybookmarks.i_time_subtitle = 0;
 
+    vlc_mutex_init( &p_sys->lock );
+
     var_AddCallback( p_intf->obj.libvlc, "key-action", ActionEvent, p_intf );
+
+    var_AddCallback( pl_Get(p_intf), "input-current", PlaylistEvent, p_intf );
+
     return VLC_SUCCESS;
 }
 
@@ -124,31 +211,24 @@ static void Close( vlc_object_t *p_this )
     intf_thread_t *p_intf = (intf_thread_t *)p_this;
     intf_sys_t *p_sys = p_intf->p_sys;
 
+    var_DelCallback( pl_Get(p_intf), "input-current", PlaylistEvent, p_intf );
+
     var_DelCallback( p_intf->obj.libvlc, "key-action", ActionEvent, p_intf );
 
+    ChangeInput( p_intf, NULL );
+
+    vlc_mutex_destroy( &p_sys->lock );
+
     /* Destroy structure */
     free( p_sys );
 }
 
-static int PutAction( intf_thread_t *p_intf, int i_action )
+static int PutAction( intf_thread_t *p_intf, input_thread_t *p_input,
+                      vout_thread_t *p_vout, int slider_chan, int i_action )
 {
     intf_sys_t *p_sys = p_intf->p_sys;
     playlist_t *p_playlist = pl_Get( p_intf );
 
-    /* Update the input */
-    input_thread_t *p_input = playlist_CurrentInput( p_playlist );
-
-    /* Update the vout */
-    vout_thread_t *p_vout = p_input ? input_GetVout( p_input ) : NULL;
-
-    /* Register OSD channels */
-    /* FIXME: this check can fail if the new vout is reallocated at the same
-     * address as the old one... We should rather listen to vout events.
-     * Alternatively, we should keep a reference to the vout thread. */
-    if( p_vout && p_vout != p_sys->p_last_vout )
-        p_sys->slider_chan = vout_RegisterSubpictureChannel( p_vout );
-    p_sys->p_last_vout = p_vout;
-
     /* Quit */
     switch( i_action )
     {
@@ -156,7 +236,7 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
         case ACTIONID_QUIT:
             libvlc_Quit( p_intf->obj.libvlc );
 
-            ClearChannels( p_intf, p_vout );
+            ClearChannels( p_vout, slider_chan );
             DisplayMessage( p_vout, _( "Quit" ) );
             break;
 
@@ -276,14 +356,14 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
         {
             float vol;
             if( playlist_VolumeUp( p_playlist, 1, &vol ) == 0 )
-                DisplayVolume( p_intf, p_vout, vol );
+                DisplayVolume( p_vout, slider_chan, vol );
             break;
         }
         case ACTIONID_VOL_DOWN:
         {
             float vol;
             if( playlist_VolumeDown( p_playlist, 1, &vol ) == 0 )
-                DisplayVolume( p_intf, p_vout, vol );
+                DisplayVolume( p_vout, slider_chan, vol );
             break;
         }
         case ACTIONID_VOL_MUTE:
@@ -298,11 +378,11 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
             float vol = playlist_VolumeGet( p_playlist );
             if( mute || vol == 0.f )
             {
-                ClearChannels( p_intf, p_vout );
+                ClearChannels( p_vout, slider_chan );
                 DisplayIcon( p_vout, OSD_MUTE_ICON );
             }
             else
-                DisplayVolume( p_intf, p_vout, vol );
+                DisplayVolume( p_vout, slider_chan, vol );
             break;
         }
 
@@ -346,7 +426,7 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
         case ACTIONID_PLAY_PAUSE:
             if( p_input )
             {
-                ClearChannels( p_intf, p_vout );
+                ClearChannels( p_vout, slider_chan );
 
                 int state = var_GetInteger( p_input, "state" );
                 DisplayIcon( p_vout, state != PAUSE_S ? OSD_PAUSE_ICON : OSD_PLAY_ICON );
@@ -360,7 +440,7 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
                 var_SetFloat( p_input, "rate", 1.f );
             else
             {
-                ClearChannels( p_intf, p_vout );
+                ClearChannels( p_vout, slider_chan );
                 DisplayIcon( p_vout, OSD_PLAY_ICON );
                 playlist_Play( p_playlist );
             }
@@ -379,7 +459,7 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
         case ACTIONID_PAUSE:
             if( p_input && var_GetInteger( p_input, "state" ) != PAUSE_S )
             {
-                ClearChannels( p_intf, p_vout );
+                ClearChannels( p_vout, slider_chan );
                 DisplayIcon( p_vout, OSD_PAUSE_ICON );
                 var_SetInteger( p_input, "state", PAUSE_S );
             }
@@ -454,7 +534,7 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
                     int64_t i_additional_subdelay = p_sys->subtitle_delaybookmarks.i_time_audio - p_sys->subtitle_delaybookmarks.i_time_subtitle;
                     int64_t i_total_subdelay = i_current_subdelay + i_additional_subdelay;
                     var_SetInteger( p_input, "spu-delay", i_total_subdelay);
-                    ClearChannels( p_intf, p_vout );
+                    ClearChannels( p_vout, slider_chan );
                     DisplayMessage( p_vout, _( "Sub sync: corrected %i ms (total delay = %i ms)" ),
                                             (int)(i_additional_subdelay / 1000),
                                             (int)(i_total_subdelay / 1000) );
@@ -467,7 +547,7 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
         case ACTIONID_SUBSYNC_RESET:
         {
             var_SetInteger( p_input, "spu-delay", 0);
-            ClearChannels( p_intf, p_vout );
+            ClearChannels( p_vout, slider_chan );
             DisplayMessage( p_vout, _( "Sub sync: delay reset" ) );
             p_sys->subtitle_delaybookmarks.i_time_audio = 0;
             p_sys->subtitle_delaybookmarks.i_time_subtitle = 0;
@@ -496,7 +576,7 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
                 int64_t i_delay = var_GetInteger( p_input, "spu-delay" ) + diff;
 
                 var_SetInteger( p_input, "spu-delay", i_delay );
-                ClearChannels( p_intf, p_vout );
+                ClearChannels( p_vout, slider_chan );
                 DisplayMessage( p_vout, _( "Subtitle delay %i ms" ),
                                 (int)(i_delay/1000) );
                 var_FreeList( &list, &list2 );
@@ -513,7 +593,7 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
                                   + diff;
 
                 var_SetInteger( p_input, "audio-delay", i_delay );
-                ClearChannels( p_intf, p_vout );
+                ClearChannels( p_vout, slider_chan );
                 DisplayMessage( p_vout, _( "Audio delay %i ms" ),
                                  (int)(i_delay/1000) );
             }
@@ -741,7 +821,7 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
             if( it < 0 )
                 break;
             var_SetInteger( p_input, "time-offset", it * sign * CLOCK_FREQ );
-            DisplayPosition( p_intf, p_vout, p_input );
+            DisplayPosition( p_vout, slider_chan, p_input );
             break;
         }
 
@@ -1151,7 +1231,7 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
                 else
                     i_pos = var_IncInteger( p_vout, "sub-margin" );
 
-                ClearChannels( p_intf, p_vout );
+                ClearChannels( p_vout, slider_chan );
                 DisplayMessage( p_vout, _( "Subtitle position %d px" ), i_pos );
                 var_FreeList( &list, &list2 );
             }
@@ -1183,14 +1263,10 @@ static int PutAction( intf_thread_t *p_intf, int i_action )
         /* Input + video output */
         case ACTIONID_POSITION:
             if( p_vout && vout_OSDEpg( p_vout, input_GetItem( p_input ) ) )
-                DisplayPosition( p_intf, p_vout, p_input );
+                DisplayPosition( p_vout, slider_chan, p_input );
             break;
     }
 
-    if( p_vout )
-        vlc_object_release( p_vout );
-    if( p_input )
-        vlc_object_release( p_input );
     return VLC_SUCCESS;
 }
 
@@ -1201,12 +1277,28 @@ static int ActionEvent( vlc_object_t *libvlc, char const *psz_var,
                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
 {
     intf_thread_t *p_intf = (intf_thread_t *)p_data;
+    intf_sys_t *p_sys = p_intf->p_sys;
 
     (void)libvlc;
     (void)psz_var;
     (void)oldval;
 
-    return PutAction( p_intf, newval.i_int );
+    vlc_mutex_lock( &p_intf->p_sys->lock );
+    input_thread_t *p_input = p_sys->p_input ? vlc_object_hold( p_sys->p_input )
+                                             : NULL;
+    vout_thread_t *p_vout = p_sys->p_vout ? vlc_object_hold( p_sys->p_vout )
+                                          : NULL;
+    int slider_chan = p_sys->slider_chan;
+    vlc_mutex_unlock( &p_intf->p_sys->lock );
+
+    int i_ret = PutAction( p_intf, p_input, p_vout, slider_chan, newval.i_int );
+
+    if( p_input != NULL )
+        vlc_object_release( p_input );
+    if( p_vout != NULL )
+        vlc_object_release( p_vout );
+
+    return i_ret;
 }
 
 static void PlayBookmark( intf_thread_t *p_intf, int i_num )
@@ -1263,7 +1355,7 @@ static void SetBookmark( intf_thread_t *p_intf, int i_num )
     free( psz_bookmark_name );
 }
 
-static void DisplayPosition( intf_thread_t *p_intf, vout_thread_t *p_vout,
+static void DisplayPosition( vout_thread_t *p_vout, int slider_chan,
                              input_thread_t *p_input )
 {
     char psz_duration[MSTRTIME_MAX_SIZE];
@@ -1271,7 +1363,7 @@ static void DisplayPosition( intf_thread_t *p_intf, vout_thread_t *p_vout,
 
     if( p_vout == NULL ) return;
 
-    ClearChannels( p_intf, p_vout );
+    ClearChannels( p_vout, slider_chan );
 
     int64_t t = var_GetInteger( p_input, "time" ) / CLOCK_FREQ;
     int64_t l = var_GetInteger( p_input, "length" ) / CLOCK_FREQ;
@@ -1292,20 +1384,19 @@ static void DisplayPosition( intf_thread_t *p_intf, vout_thread_t *p_vout,
     {
         vlc_value_t pos;
         var_Get( p_input, "position", &pos );
-        vout_OSDSlider( p_vout, p_intf->p_sys->slider_chan,
+        vout_OSDSlider( p_vout, slider_chan,
                         pos.f_float * 100, OSD_HOR_SLIDER );
     }
 }
 
-static void DisplayVolume( intf_thread_t *p_intf, vout_thread_t *p_vout,
-                           float vol )
+static void DisplayVolume( vout_thread_t *p_vout, int slider_chan, float vol )
 {
     if( p_vout == NULL )
         return;
-    ClearChannels( p_intf, p_vout );
+    ClearChannels( p_vout, slider_chan );
 
     if( var_GetBool( p_vout, "fullscreen" ) )
-        vout_OSDSlider( p_vout, p_intf->p_sys->slider_chan,
+        vout_OSDSlider( p_vout, slider_chan,
                         lroundf(vol * 100.f), OSD_VERT_SLIDER );
     DisplayMessage( p_vout, _( "Volume %ld%%" ), lroundf(vol * 100.f) );
 }
@@ -1334,11 +1425,11 @@ static float AdjustRateFine( vlc_object_t *p_obj, const int i_dir )
     return f_rate;
 }
 
-static void ClearChannels( intf_thread_t *p_intf, vout_thread_t *p_vout )
+static void ClearChannels( vout_thread_t *p_vout, int slider_chan )
 {
     if( p_vout )
     {
         vout_FlushSubpictureChannel( p_vout, SPU_DEFAULT_CHANNEL );
-        vout_FlushSubpictureChannel( p_vout, p_intf->p_sys->slider_chan );
+        vout_FlushSubpictureChannel( p_vout, slider_chan );
     }
 }