Commit 450c0776 authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

EventManager: Provide an easier way to unregister events

parent 6d3e41e9
......@@ -29,10 +29,10 @@
#include "common.hpp"
#include "Internal.hpp"
#include <algorithm>
#include <functional>
#include <unordered_map>
#include <vector>
#include <memory>
#include <atomic>
#define EXPECT_SIGNATURE(sig) static_assert(signature_match<decltype(f), sig>::value, "Expected a function with prototype " #sig)
......@@ -41,8 +41,6 @@ namespace VLC
class Media;
using EventToken = unsigned int;
/**
* @brief This class serves as a base for all event managers.
*
......@@ -62,6 +60,7 @@ protected:
template <typename, typename, typename = void>
struct signature_match : std::false_type {};
// Kudos to 3xxO
template <typename Func, typename Ret, typename... Args>
struct signature_match<Func, Ret(Args...),
typename std::enable_if<
......@@ -78,8 +77,11 @@ private:
{
using Wrapper = std::add_pointer<void(const libvlc_event_t*, void*)>::type;
virtual ~EventHandlerBase() {}
virtual void unregister() = 0;
};
using RegisteredEvent = EventHandlerBase&;
template <typename Func>
class EventHandler : public EventHandlerBase
{
......@@ -96,9 +98,16 @@ private:
~EventHandler()
{
// We unregister only when the object actually goes out of scope, IE. when it is
// removed from EventManager's event handler vector
libvlc_event_detach( *m_eventManager, m_eventType, m_wrapper, &m_userCallback );
}
virtual void unregister() override
{
m_eventManager->unregister(*this);
}
EventHandler(const EventHandler&) = delete;
private:
......@@ -109,24 +118,48 @@ private:
libvlc_event_e m_eventType;
};
public:
void unregister(const RegisteredEvent e)
{
auto it = std::find_if(begin(m_lambdas), end(m_lambdas), [&e](decltype(m_lambdas)::value_type &value) {
return &e == value.get();
});
if (it != end(m_lambdas))
m_lambdas.erase( it );
}
protected:
EventManager(InternalPtr ptr)
: Internal{ ptr, [](InternalPtr){ /* No-op; EventManager's are handled by their respective objects */ } }
, m_lastEvent(0)
{
}
/**
* @brief handle Provides the common behavior for all event handlers
* @param eventType The libvlc type of event
* @param f The user provided std::function. This has to either match the expected parameter list
* exactly, or it can take no arguments.
* @param wrapper Our implementation defined wrapper around the user's callback. It is expected to be able
* able to decay to a regular C-style function pointer. It is currently implemented as a
* captureless lambda (§5.1.2)
* @return A reference to an abstract EventHandler type. It is assumed that the EventManager will
* outlive this reference. When EventManager::~EventManager is called, it will destroy all
* the registered event handler, this making this reference a dangling reference, which is
* undefined behavior.
* When calling unregister() on this object, the reference should immediatly be considered invalid.
*/
template <typename Func>
EventToken handle(libvlc_event_e eventType, Func&& f, EventHandlerBase::Wrapper wrapper)
RegisteredEvent handle(libvlc_event_e eventType, Func&& f, EventHandlerBase::Wrapper wrapper)
{
auto token = ++m_lastEvent;
m_lambdas[token] = std::unique_ptr<EventHandlerBase>( new EventHandler<Func>(
*this, eventType, std::forward<Func>( f ), wrapper ) );
return token;
auto ptr = std::unique_ptr<EventHandlerBase>( new EventHandler<Func>(
*this, eventType, std::forward<Func>( f ), wrapper ) );
auto raw = ptr.get();
m_lambdas.push_back( std::move( ptr ) );
return *raw;
}
template <typename Func>
EventToken handle(libvlc_event_e eventType, Func&& f)
RegisteredEvent handle(libvlc_event_e eventType, Func&& f)
{
EXPECT_SIGNATURE(void());
return handle(eventType, std::forward<Func>( f ), [](const libvlc_event_t*, void* data)
......@@ -136,18 +169,10 @@ protected:
});
}
void unregister(EventToken t)
{
if (t == 0)
return;
m_lambdas.erase(t);
}
protected:
// We store the EventHandlerBase's as unique_ptr in order for the function stored within
// EventHandler<T> not to move to another memory location
std::unordered_map<EventToken, std::unique_ptr<EventHandlerBase>> m_lambdas;
std::atomic_uint m_lastEvent;
std::vector<std::unique_ptr<EventHandlerBase>> m_lambdas;
};
class MediaEventManager : public EventManager
......@@ -160,7 +185,7 @@ class MediaEventManager : public EventManager
* @param f A std::function<void(libvlc_meta_t)>
*/
template <typename Func>
EventToken onMetaChanged( Func&& f)
RegisteredEvent onMetaChanged( Func&& f)
{
EXPECT_SIGNATURE(void(libvlc_meta_t));
return handle( libvlc_MediaMetaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -175,7 +200,7 @@ class MediaEventManager : public EventManager
* @param f A std::function<void(MediaPtr)>
*/
template <typename Func>
EventToken onSubItemAdded( Func&& f )
RegisteredEvent onSubItemAdded( Func&& f )
{
EXPECT_SIGNATURE(void(MediaPtr));
return handle(libvlc_MediaSubItemAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -186,7 +211,7 @@ class MediaEventManager : public EventManager
}
template <typename Func>
EventToken onDurationChanged( Func&& f )
RegisteredEvent onDurationChanged( Func&& f )
{
EXPECT_SIGNATURE(void(int64_t));
return handle(libvlc_MediaDurationChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -197,7 +222,7 @@ class MediaEventManager : public EventManager
}
template <typename Func>
EventToken onParsedChanged( Func&& f )
RegisteredEvent onParsedChanged( Func&& f )
{
EXPECT_SIGNATURE(void(bool));
return handle( libvlc_MediaParsedChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -208,7 +233,7 @@ class MediaEventManager : public EventManager
}
template <typename Func>
EventToken onFreed( Func&& f)
RegisteredEvent onFreed( Func&& f)
{
EXPECT_SIGNATURE(void(MediaPtr));
return handle(libvlc_MediaFreed, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -219,7 +244,7 @@ class MediaEventManager : public EventManager
}
template <typename Func>
EventToken onStateChanged( Func&& f)
RegisteredEvent onStateChanged( Func&& f)
{
EXPECT_SIGNATURE(void(libvlc_state_t));
return handle(libvlc_MediaStateChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -230,7 +255,7 @@ class MediaEventManager : public EventManager
}
template <typename Func>
EventToken onSubItemTreeAdded( Func&& f)
RegisteredEvent onSubItemTreeAdded( Func&& f)
{
EXPECT_SIGNATURE(void(MediaPtr));
return handle(libvlc_MediaSubItemAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -247,7 +272,7 @@ class MediaPlayerEventManager : public EventManager
MediaPlayerEventManager(InternalPtr ptr) : EventManager( ptr ) {}
template <typename Func>
EventToken onMediaChanged( Func&& f )
RegisteredEvent onMediaChanged( Func&& f )
{
EXPECT_SIGNATURE(void(MediaPtr));
return handle(libvlc_MediaPlayerMediaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -258,67 +283,67 @@ class MediaPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onNothingSpecial( Func&& f )
RegisteredEvent onNothingSpecial( Func&& f )
{
return handle(libvlc_MediaPlayerNothingSpecial, std::forward<Func>( f ));
}
template <typename Func>
EventToken onOpening( Func&& f )
RegisteredEvent onOpening( Func&& f )
{
return handle(libvlc_MediaPlayerOpening, std::forward<Func>( f ) );
}
template <typename Func>
EventToken onBuffering( Func&& f )
RegisteredEvent onBuffering( Func&& f )
{
return handle(libvlc_MediaPlayerBuffering, std::forward<Func>( f ) );
}
template <typename Func>
EventToken onPlaying( Func&& f )
RegisteredEvent onPlaying( Func&& f )
{
return handle( libvlc_MediaPlayerPlaying, std::forward<Func>( f ) );
}
template <typename Func>
EventToken onPaused(Func&& f)
RegisteredEvent onPaused(Func&& f)
{
return handle( libvlc_MediaPlayerPaused, std::forward<Func>( f ) );
}
template <typename Func>
EventToken onStopped(Func&& f)
RegisteredEvent onStopped(Func&& f)
{
return handle( libvlc_MediaPlayerStopped, std::forward<Func>( f ) );
}
template <typename Func>
EventToken onForward(Func&& f)
RegisteredEvent onForward(Func&& f)
{
return handle( libvlc_MediaPlayerForward, std::forward<Func>( f ) );
}
template <typename Func>
EventToken onBackward(Func&& f)
RegisteredEvent onBackward(Func&& f)
{
return handle( libvlc_MediaPlayerBackward, std::forward<Func>( f ) );
}
template <typename Func>
EventToken onEndReached(Func&& f)
RegisteredEvent onEndReached(Func&& f)
{
return handle( libvlc_MediaPlayerEndReached, std::forward<Func>( f ) );
}
template <typename Func>
EventToken onEncounteredError(Func&& f)
RegisteredEvent onEncounteredError(Func&& f)
{
return handle( libvlc_MediaPlayerEncounteredError, std::forward<Func>( f ) );
}
template <typename Func>
EventToken onTimeChanged( Func&& f )
RegisteredEvent onTimeChanged( Func&& f )
{
EXPECT_SIGNATURE(void(libvlc_time_t));
return handle( libvlc_MediaPlayerTimeChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -329,7 +354,7 @@ class MediaPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onPositionChanged( Func&& f )
RegisteredEvent onPositionChanged( Func&& f )
{
EXPECT_SIGNATURE(void(float));
return handle( libvlc_MediaPlayerPositionChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -340,7 +365,7 @@ class MediaPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onSeekableChanged( Func&& f )
RegisteredEvent onSeekableChanged( Func&& f )
{
EXPECT_SIGNATURE(void(bool));
return handle( libvlc_MediaPlayerSeekableChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -351,7 +376,7 @@ class MediaPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onPausableChanged( Func&& f )
RegisteredEvent onPausableChanged( Func&& f )
{
EXPECT_SIGNATURE(void(bool));
return handle( libvlc_MediaPlayerSeekableChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -362,7 +387,7 @@ class MediaPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onTitleChanged( Func&& f )
RegisteredEvent onTitleChanged( Func&& f )
{
EXPECT_SIGNATURE(void(int));
return handle( libvlc_MediaPlayerTitleChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -373,7 +398,7 @@ class MediaPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onSnapshotTaken( Func&& f )
RegisteredEvent onSnapshotTaken( Func&& f )
{
EXPECT_SIGNATURE(void(std::string));
return handle( libvlc_MediaPlayerSnapshotTaken, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -384,7 +409,7 @@ class MediaPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onLengthChanged( Func&& f )
RegisteredEvent onLengthChanged( Func&& f )
{
EXPECT_SIGNATURE(void(libvlc_time_t));
return handle( libvlc_MediaPlayerLengthChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -395,7 +420,7 @@ class MediaPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onVout( Func&& f )
RegisteredEvent onVout( Func&& f )
{
EXPECT_SIGNATURE(void(int));
return handle( libvlc_MediaPlayerVout, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -406,7 +431,7 @@ class MediaPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onScrambledChanged( Func&& f )
RegisteredEvent onScrambledChanged( Func&& f )
{
EXPECT_SIGNATURE(void(int));
return handle( libvlc_MediaPlayerScrambledChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -417,7 +442,7 @@ class MediaPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onESAdded( Func&& f )
RegisteredEvent onESAdded( Func&& f )
{
EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
return handle( libvlc_MediaPlayerESAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -428,7 +453,7 @@ class MediaPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onESDeleted( Func&& f )
RegisteredEvent onESDeleted( Func&& f )
{
EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
return handle( libvlc_MediaPlayerESDeleted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -439,7 +464,7 @@ class MediaPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onESSelected( Func&& f )
RegisteredEvent onESSelected( Func&& f )
{
EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
return handle( libvlc_MediaPlayerESSelected, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -456,7 +481,7 @@ class MediaListEventManager : public EventManager
MediaListEventManager(InternalPtr ptr) : EventManager( ptr ) {}
template <typename Func>
EventToken onItemAdded( Func&& f )
RegisteredEvent onItemAdded( Func&& f )
{
EXPECT_SIGNATURE(void(MediaPtr, int));
return handle(libvlc_MediaListItemAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -467,7 +492,7 @@ class MediaListEventManager : public EventManager
}
template <typename Func>
EventToken onWillAddItem( Func&& f )
RegisteredEvent onWillAddItem( Func&& f )
{
EXPECT_SIGNATURE(void(MediaPtr, int));
return handle( libvlc_MediaListWillAddItem, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -478,7 +503,7 @@ class MediaListEventManager : public EventManager
}
template <typename Func>
EventToken onItemDeleted( Func&& f )
RegisteredEvent onItemDeleted( Func&& f )
{
EXPECT_SIGNATURE(void(MediaPtr, int));
return handle(libvlc_MediaListItemDeleted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -489,7 +514,7 @@ class MediaListEventManager : public EventManager
}
template <typename Func>
EventToken onWillDeleteItem( Func&& f )
RegisteredEvent onWillDeleteItem( Func&& f )
{
EXPECT_SIGNATURE(void(MediaPtr, int));
return handle(libvlc_MediaListWillDeleteItem, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -508,13 +533,13 @@ class MediaListPlayerEventManager : public EventManager
MediaListPlayerEventManager(InternalPtr ptr) : EventManager( ptr ) {}
template <typename Func>
EventToken onPlayed(Func&& f)
RegisteredEvent onPlayed(Func&& f)
{
return handle(libvlc_MediaListPlayerPlayed, std::forward<Func>( f ) );
}
template <typename Func>
EventToken onNextItemSet( Func&& f )
RegisteredEvent onNextItemSet( Func&& f )
{
EXPECT_SIGNATURE(void(MediaPtr));
return handle(libvlc_MediaListPlayerNextItemSet, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -525,7 +550,7 @@ class MediaListPlayerEventManager : public EventManager
}
template <typename Func>
EventToken onStopped( Func&& f )
RegisteredEvent onStopped( Func&& f )
{
return handle(libvlc_MediaListPlayerStopped, std::forward<Func>( f ) );
}
......@@ -537,13 +562,13 @@ class MediaDiscovererEventManager : public EventManager
MediaDiscovererEventManager(InternalPtr ptr) : EventManager( ptr ) {}
template <typename Func>
EventToken onStarted(Func&& f)
RegisteredEvent onStarted(Func&& f)
{
return handle(libvlc_MediaDiscovererStarted, std::forward<Func>( f ) );
}
template <typename Func>
EventToken onStopped(Func&& f)
RegisteredEvent onStopped(Func&& f)
{
return handle(libvlc_MediaDiscovererEnded, std::forward<Func>( f ) );
}
......@@ -555,7 +580,7 @@ class VLMEventManager : public EventManager
using EventManager::EventManager;
template <typename Func>
EventToken onMediaAdded( Func&& f )
RegisteredEvent onMediaAdded( Func&& f )
{
EXPECT_SIGNATURE(void(std::string));
return handle(libvlc_VlmMediaAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -566,7 +591,7 @@ class VLMEventManager : public EventManager
}
template <typename Func>
EventToken onMediaRemoved( Func&& f )
RegisteredEvent onMediaRemoved( Func&& f )
{
EXPECT_SIGNATURE(void(std::string));
return handle(libvlc_VlmMediaRemoved, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -577,7 +602,7 @@ class VLMEventManager : public EventManager
}
template <typename Func>
EventToken onMediaChanged( Func&& f )
RegisteredEvent onMediaChanged( Func&& f )
{
EXPECT_SIGNATURE(void(std::string));
return handle(libvlc_VlmMediaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -588,7 +613,7 @@ class VLMEventManager : public EventManager
}
template <typename Func>
EventToken onMediaInstanceStarted( Func&& f )
RegisteredEvent onMediaInstanceStarted( Func&& f )
{
EXPECT_SIGNATURE(void(std::string, std::string));
return handle(libvlc_VlmMediaInstanceStarted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -600,7 +625,7 @@ class VLMEventManager : public EventManager
}
template <typename Func>
EventToken onMediaInstanceStopped( Func&& f )
RegisteredEvent onMediaInstanceStopped( Func&& f )
{
EXPECT_SIGNATURE(void(std::string, std::string));
return handle(libvlc_VlmMediaInstanceStopped, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -612,7 +637,7 @@ class VLMEventManager : public EventManager
}
template <typename Func>
EventToken onMediaInstanceStatusInit( Func&& f )
RegisteredEvent onMediaInstanceStatusInit( Func&& f )
{
EXPECT_SIGNATURE(void(std::string, std::string));
return handle(libvlc_VlmMediaInstanceStatusInit, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -624,7 +649,7 @@ class VLMEventManager : public EventManager
}
template <typename Func>
EventToken onMediaInstanceStatusOpening( Func&& f )
RegisteredEvent onMediaInstanceStatusOpening( Func&& f )
{
EXPECT_SIGNATURE(void(std::string, std::string));
return handle(libvlc_VlmMediaInstanceStatusOpening, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -636,7 +661,7 @@ class VLMEventManager : public EventManager
}
template <typename Func>
EventToken onMediaInstanceStatusPlaying( Func&& f )
RegisteredEvent onMediaInstanceStatusPlaying( Func&& f )
{
EXPECT_SIGNATURE(void(std::string, std::string));
return handle(libvlc_VlmMediaInstanceStatusPlaying, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -648,7 +673,7 @@ class VLMEventManager : public EventManager
}
template <typename Func>
EventToken onMediaInstanceStatusPause( Func&& f )
RegisteredEvent onMediaInstanceStatusPause( Func&& f )
{
EXPECT_SIGNATURE(void(std::string, std::string));
return handle(libvlc_VlmMediaInstanceStatusPause, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -660,7 +685,7 @@ class VLMEventManager : public EventManager
}
template <typename Func>
EventToken onMediaInstanceStatusEnd( Func&& f )
RegisteredEvent onMediaInstanceStatusEnd( Func&& f )
{
EXPECT_SIGNATURE(void(std::string, std::string));
return handle(libvlc_VlmMediaInstanceStatusEnd, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......@@ -672,7 +697,7 @@ class VLMEventManager : public EventManager
}
template <typename Func>
EventToken onMediaInstanceStatusError( Func&& f )
RegisteredEvent onMediaInstanceStatusError( Func&& f )
{
EXPECT_SIGNATURE(void(std::string, std::string));
return handle(libvlc_VlmMediaInstanceStatusError, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
......
......@@ -32,6 +32,19 @@ int main(int ac, char** av)
*/
mp.play();
std::this_thread::sleep_for( std::chrono::seconds( 10 ) );
bool expected = true;
auto& handler = mp.eventManager()->onPositionChanged([&expected](float pos) {
std::cout << "position changed " << pos << std::endl;
assert(expected);
});
std::this_thread::sleep_for( std::chrono::seconds( 2 ) );
handler.unregister();
// handler must be considered a dangling reference from now on.
// We might want to fix this, but is it worth the cost of a shared/weak_pointer?
expected = false;
std::this_thread::sleep_for( std::chrono::seconds( 2 ) );
mp.stop();
}
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