]> git.sesse.net Git - vlc/commitdiff
skins2: improve callback system
authorErwan Tulou <erwan10@videolan.org>
Wed, 28 Jul 2010 20:37:51 +0000 (22:37 +0200)
committerErwan Tulou <erwan10@videolan.org>
Sat, 31 Jul 2010 16:03:17 +0000 (18:03 +0200)
This patch is mainly intended to work out the async queue getting
bigger and bigger when skins cannot keep up with command processing.
Since flushing the queue is an infinite loop, this ends up in vlc
hanging (frozen GUI). This happens when skins are complex (many controls,
many timers, animated images, scrolling text, ...)

With this patch, new commands of a given type can now replace pending
commands not yet processed when that makes sense (e.g position, volume, ...).
The position is really the one responsible for overflooding the queue.

modules/gui/skins2/commands/cmd_callbacks.hpp
modules/gui/skins2/src/vlcproc.cpp
modules/gui/skins2/src/vlcproc.hpp

index 579c6fa3729ec5435be4e569b15b5f4a6cdf91f0..ff222bb2bd2acf1fd8735e5da04d142f3fa5164d 100644 (file)
 #include "cmd_generic.hpp"
 #include "../src/vlcproc.hpp"
 
-class CmdLabeled : public CmdGeneric
-{
-private:
-    vlc_object_t *m_pObj;
-    vlc_value_t   m_newVal;
-protected:
-    void execute_on( void (VlcProc::*on_label)(vlc_object_t *,vlc_value_t) )
-    {
-        if( !m_pObj )
-            return;
-
-        (VlcProc::instance( getIntf() )->*on_label)( m_pObj, m_newVal );
 
-        vlc_object_release( m_pObj );
-        m_pObj =  NULL;
-    }
-    CmdLabeled( intf_thread_t *pIntf, vlc_object_t *pObj, vlc_value_t newVal )
-              : CmdGeneric( pIntf ), m_pObj( pObj ), m_newVal( newVal )
+class CmdCallback : public CmdGeneric
+{
+public:
+    CmdCallback( intf_thread_t *pIntf, vlc_object_t *pObj, vlc_value_t newVal,
+                 void (VlcProc::*func)(vlc_object_t *,vlc_value_t),
+                 string label )
+        : CmdGeneric( pIntf ), m_pObj( pObj ), m_newVal( newVal ),
+          m_pfExecute( func ), m_label( label )
     {
         if( m_pObj )
             vlc_object_hold( m_pObj );
     }
-public:
-    virtual ~CmdLabeled() {
+    virtual ~CmdCallback()
+    {
         if( m_pObj )
             vlc_object_release( m_pObj );
     }
-};
-
-#define ADD_COMMAND( label )                                            \
-    class Cmd_##label : public CmdLabeled                               \
-    {   public:                                                         \
-        Cmd_##label( intf_thread_t *I, vlc_object_t *O, vlc_value_t V ) \
-                   : CmdLabeled (I, O, V) { }                           \
-        virtual string getType() const { return #label; }               \
-        virtual void execute() { execute_on( &VlcProc::on_##label ); }  \
-    };
-
-ADD_COMMAND( item_current_changed )
-ADD_COMMAND( intf_event_changed )
-ADD_COMMAND( bit_rate_changed )
-ADD_COMMAND( sample_rate_changed )
-ADD_COMMAND( can_record_changed )
-
-ADD_COMMAND( random_changed )
-ADD_COMMAND( loop_changed )
-ADD_COMMAND( repeat_changed )
-
-ADD_COMMAND( volume_changed )
+    virtual void execute()
+    {
+        if( !m_pObj || !m_pfExecute )
+            return;
 
-ADD_COMMAND( audio_filter_changed )
+        (VlcProc::instance( getIntf() )->*m_pfExecute)( m_pObj, m_newVal );
 
-ADD_COMMAND( intf_show_changed )
+        vlc_object_release( m_pObj );
+        m_pObj = NULL;
+    }
+    virtual string getType() const { return m_label; }
 
-#undef ADD_COMMAND
+private:
+    vlc_object_t* m_pObj;
+    vlc_value_t   m_newVal;
+    string        m_label;
+    void (VlcProc::*m_pfExecute)(vlc_object_t *,vlc_value_t);
+};
 
 #endif
index 78f58c7f399c45761b62c6e36771871a7a9be0a3..a0a0e34f1b3a24875261d0347fc7c1c582ac23b9 100644 (file)
@@ -254,7 +254,7 @@ int VlcProc::onInputNew( vlc_object_t *pObj, const char *pVariable,
     VlcProc *pThis = (VlcProc*)pParam;
     input_thread_t *pInput = static_cast<input_thread_t*>(newval.p_address);
 
-    var_AddCallback( pInput, "intf-event", onGenericCallback, pThis );
+    var_AddCallback( pInput, "intf-event", onGenericCallback2, pThis );
     var_AddCallback( pInput, "bit-rate", onGenericCallback, pThis );
     var_AddCallback( pInput, "sample-rate", onGenericCallback, pThis );
     var_AddCallback( pInput, "can-record", onGenericCallback, pThis );
@@ -375,40 +375,92 @@ int VlcProc::onGenericCallback( vlc_object_t *pObj, const char *pVariable,
     VlcProc *pThis = (VlcProc*)pParam;
     AsyncQueue *pQueue = AsyncQueue::instance( pThis->getIntf() );
 
-    CmdGeneric *pCmd = NULL;
-
-#define ADD_CALLBACK_ENTRY( var, label ) \
+#define ADD_CALLBACK_ENTRY( var, func, remove ) \
     { \
     if( strcmp( pVariable, var ) == 0 ) \
-        pCmd = new Cmd_##label( pThis->getIntf(), pObj, newVal ); \
+    { \
+        string label = var; \
+        CmdGeneric *pCmd = new CmdCallback( pThis->getIntf(), pObj, newVal, \
+                                            &VlcProc::func, label ); \
+        if( pCmd ) \
+            pQueue->push( CmdGenericPtr( pCmd ), remove ); \
+        return VLC_SUCCESS; \
+    } \
     }
 
-    ADD_CALLBACK_ENTRY( "item-current", item_current_changed )
-    ADD_CALLBACK_ENTRY( "volume-change", volume_changed )
+    ADD_CALLBACK_ENTRY( "item-current", on_item_current_changed, false )
+    ADD_CALLBACK_ENTRY( "volume-change", on_volume_changed, true )
 
-    ADD_CALLBACK_ENTRY( "intf-event", intf_event_changed )
-    ADD_CALLBACK_ENTRY( "bit-rate", bit_rate_changed )
-    ADD_CALLBACK_ENTRY( "sample-rate", sample_rate_changed )
-    ADD_CALLBACK_ENTRY( "can-record", can_record_changed )
+    ADD_CALLBACK_ENTRY( "bit-rate", on_bit_rate_changed, false )
+    ADD_CALLBACK_ENTRY( "sample-rate", on_sample_rate_changed, false )
+    ADD_CALLBACK_ENTRY( "can-record", on_can_record_changed, false )
 
-    ADD_CALLBACK_ENTRY( "random", random_changed )
-    ADD_CALLBACK_ENTRY( "loop", loop_changed )
-    ADD_CALLBACK_ENTRY( "repeat", repeat_changed )
+    ADD_CALLBACK_ENTRY( "random", on_random_changed, false )
+    ADD_CALLBACK_ENTRY( "loop", on_loop_changed, false )
+    ADD_CALLBACK_ENTRY( "repeat", on_repeat_changed, false )
 
-    ADD_CALLBACK_ENTRY( "audio-filter", audio_filter_changed )
+    ADD_CALLBACK_ENTRY( "audio-filter", on_audio_filter_changed, false )
 
-    ADD_CALLBACK_ENTRY( "intf-show", intf_show_changed )
+    ADD_CALLBACK_ENTRY( "intf-show", on_intf_show_changed, false )
 
 #undef ADD_CALLBACK_ENTRY
 
-    if( pCmd )
-        pQueue->push( CmdGenericPtr( pCmd ), false );
-    else
-        msg_Err( pObj, "no Callback entry provided for %s", pVariable );
+    msg_Err( pThis->getIntf(), "no callback entry for %s", pVariable );
+    return VLC_EGENERIC;
+}
 
-    return VLC_SUCCESS;
+
+int VlcProc::onGenericCallback2( vlc_object_t *pObj, const char *pVariable,
+                                 vlc_value_t oldVal, vlc_value_t newVal,
+                                 void *pParam )
+{
+    VlcProc *pThis = (VlcProc*)pParam;
+    AsyncQueue *pQueue = AsyncQueue::instance( pThis->getIntf() );
+
+    /**
+     * For intf-event, commands are labeled based on the value of newVal.
+     *
+     * For some values (e.g position), only keep the latest command
+     * when there are multiple pending commands (remove=true).
+     *
+     * for others, don't discard commands (remove=false)
+     **/
+    if( strcmp( pVariable, "intf-event" ) == 0 )
+    {
+        stringstream label;
+        bool b_remove;
+        switch( newVal.i_int )
+        {
+            case INPUT_EVENT_STATE:
+            case INPUT_EVENT_POSITION:
+            case INPUT_EVENT_ES:
+            case INPUT_EVENT_CHAPTER:
+            case INPUT_EVENT_RECORD:
+                b_remove = true;
+                break;
+            case INPUT_EVENT_VOUT:
+            case INPUT_EVENT_AOUT:
+            case INPUT_EVENT_DEAD:
+                b_remove = false;
+                break;
+            default:
+                return VLC_SUCCESS;
+        }
+        label <<  pVariable << "_" << newVal.i_int;
+        CmdGeneric *pCmd = new CmdCallback( pThis->getIntf(), pObj, newVal,
+                                            &VlcProc::on_intf_event_changed,
+                                            label.str() );
+        if( pCmd )
+            pQueue->push( CmdGenericPtr( pCmd ), b_remove );
+
+        return VLC_SUCCESS;
+    }
+
+    msg_Err( pThis->getIntf(), "no callback entry for %s", pVariable );
+    return VLC_EGENERIC;
 }
 
+
 #define SET_BOOL(m,v)         ((VarBoolImpl*)(m).get())->set(v)
 #define SET_STREAMTIME(m,v,b) ((StreamTime*)(m).get())->set(v,b)
 #define SET_TEXT(m,v)         ((VarText*)(m).get())->set(v)
@@ -554,7 +606,7 @@ void VlcProc::on_intf_event_changed( vlc_object_t* p_obj, vlc_value_t newVal )
         case INPUT_EVENT_DEAD:
             msg_Dbg( getIntf(), "end of input detected for %p", pInput );
 
-            var_DelCallback( pInput, "intf-event", onGenericCallback, this );
+            var_DelCallback( pInput, "intf-event", onGenericCallback2, this );
             var_DelCallback( pInput, "bit-rate", onGenericCallback, this );
             var_DelCallback( pInput, "sample-rate", onGenericCallback, this );
             var_DelCallback( pInput, "can-record" , onGenericCallback, this );
index 1a19bcb8e664f80fc4d50f3d7ddaf2a81c343a87..64c79420ef6bba37b7c78c0ca2f681d8c5c5156c 100644 (file)
@@ -221,6 +221,10 @@ private:
                                   vlc_value_t oldVal, vlc_value_t newVal,
                                   void *pParam );
 
+    /// Generic Callback for intf-event
+    static int onGenericCallback2( vlc_object_t *pObj, const char *pVariable,
+                                   vlc_value_t oldVal, vlc_value_t newVal,
+                                   void *pParam );
 };