Commit 50200d70 authored by Erwan Tulou's avatar Erwan Tulou

skins2: improve callback system

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.
parent e13aa916
...@@ -28,60 +28,41 @@ ...@@ -28,60 +28,41 @@
#include "cmd_generic.hpp" #include "cmd_generic.hpp"
#include "../src/vlcproc.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 ); class CmdCallback : public CmdGeneric
m_pObj = NULL; {
} public:
CmdLabeled( intf_thread_t *pIntf, vlc_object_t *pObj, vlc_value_t newVal ) CmdCallback( intf_thread_t *pIntf, vlc_object_t *pObj, vlc_value_t newVal,
: CmdGeneric( pIntf ), m_pObj( pObj ), m_newVal( 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 ) if( m_pObj )
vlc_object_hold( m_pObj ); vlc_object_hold( m_pObj );
} }
public: virtual ~CmdCallback()
virtual ~CmdLabeled() { {
if( m_pObj ) if( m_pObj )
vlc_object_release( m_pObj ); vlc_object_release( m_pObj );
} }
}; virtual void execute()
{
#define ADD_COMMAND( label ) \ if( !m_pObj || !m_pfExecute )
class Cmd_##label : public CmdLabeled \ return;
{ 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 )
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 #endif
...@@ -254,7 +254,7 @@ int VlcProc::onInputNew( vlc_object_t *pObj, const char *pVariable, ...@@ -254,7 +254,7 @@ int VlcProc::onInputNew( vlc_object_t *pObj, const char *pVariable,
VlcProc *pThis = (VlcProc*)pParam; VlcProc *pThis = (VlcProc*)pParam;
input_thread_t *pInput = static_cast<input_thread_t*>(newval.p_address); 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, "bit-rate", onGenericCallback, pThis );
var_AddCallback( pInput, "sample-rate", onGenericCallback, pThis ); var_AddCallback( pInput, "sample-rate", onGenericCallback, pThis );
var_AddCallback( pInput, "can-record", onGenericCallback, pThis ); var_AddCallback( pInput, "can-record", onGenericCallback, pThis );
...@@ -375,40 +375,92 @@ int VlcProc::onGenericCallback( vlc_object_t *pObj, const char *pVariable, ...@@ -375,40 +375,92 @@ int VlcProc::onGenericCallback( vlc_object_t *pObj, const char *pVariable,
VlcProc *pThis = (VlcProc*)pParam; VlcProc *pThis = (VlcProc*)pParam;
AsyncQueue *pQueue = AsyncQueue::instance( pThis->getIntf() ); AsyncQueue *pQueue = AsyncQueue::instance( pThis->getIntf() );
CmdGeneric *pCmd = NULL; #define ADD_CALLBACK_ENTRY( var, func, remove ) \
#define ADD_CALLBACK_ENTRY( var, label ) \
{ \ { \
if( strcmp( pVariable, var ) == 0 ) \ 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( "item-current", on_item_current_changed, false )
ADD_CALLBACK_ENTRY( "volume-change", volume_changed ) ADD_CALLBACK_ENTRY( "volume-change", on_volume_changed, true )
ADD_CALLBACK_ENTRY( "intf-event", intf_event_changed ) ADD_CALLBACK_ENTRY( "bit-rate", on_bit_rate_changed, false )
ADD_CALLBACK_ENTRY( "bit-rate", bit_rate_changed ) ADD_CALLBACK_ENTRY( "sample-rate", on_sample_rate_changed, false )
ADD_CALLBACK_ENTRY( "sample-rate", sample_rate_changed ) ADD_CALLBACK_ENTRY( "can-record", on_can_record_changed, false )
ADD_CALLBACK_ENTRY( "can-record", can_record_changed )
ADD_CALLBACK_ENTRY( "random", random_changed ) ADD_CALLBACK_ENTRY( "random", on_random_changed, false )
ADD_CALLBACK_ENTRY( "loop", loop_changed ) ADD_CALLBACK_ENTRY( "loop", on_loop_changed, false )
ADD_CALLBACK_ENTRY( "repeat", repeat_changed ) 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 #undef ADD_CALLBACK_ENTRY
if( pCmd ) msg_Err( pThis->getIntf(), "no callback entry for %s", pVariable );
pQueue->push( CmdGenericPtr( pCmd ), false ); return VLC_EGENERIC;
else }
msg_Err( pObj, "no Callback entry provided for %s", pVariable );
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_BOOL(m,v) ((VarBoolImpl*)(m).get())->set(v)
#define SET_STREAMTIME(m,v,b) ((StreamTime*)(m).get())->set(v,b) #define SET_STREAMTIME(m,v,b) ((StreamTime*)(m).get())->set(v,b)
#define SET_TEXT(m,v) ((VarText*)(m).get())->set(v) #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 ) ...@@ -554,7 +606,7 @@ void VlcProc::on_intf_event_changed( vlc_object_t* p_obj, vlc_value_t newVal )
case INPUT_EVENT_DEAD: case INPUT_EVENT_DEAD:
msg_Dbg( getIntf(), "end of input detected for %p", pInput ); 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, "bit-rate", onGenericCallback, this );
var_DelCallback( pInput, "sample-rate", onGenericCallback, this ); var_DelCallback( pInput, "sample-rate", onGenericCallback, this );
var_DelCallback( pInput, "can-record" , onGenericCallback, this ); var_DelCallback( pInput, "can-record" , onGenericCallback, this );
......
...@@ -221,6 +221,10 @@ private: ...@@ -221,6 +221,10 @@ private:
vlc_value_t oldVal, vlc_value_t newVal, vlc_value_t oldVal, vlc_value_t newVal,
void *pParam ); 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 );
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment