EventManager.hpp 44.1 KB
Newer Older
1
/*****************************************************************************
2
 * EventManager.hpp: Exposes libvlc events
3
 *****************************************************************************
4
 * Copyright © 2015 libvlcpp authors & VideoLAN
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifndef LIBVLC_EVENTMANAGER_HPP
#define LIBVLC_EVENTMANAGER_HPP

#include <string>
27

28
#include "common.hpp"
29
#include "Internal.hpp"
30

31
#include <algorithm>
32
#include <functional>
33
#include <vector>
34 35
#include <memory>

36 37
#define EXPECT_SIGNATURE(sig) static_assert(signature_match<decltype(f), sig>::value, "Expected a function with prototype " #sig)

38 39 40 41 42
namespace VLC
{

class Media;

43 44 45
/**
 * @brief This class serves as a base for all event managers.
 *
46 47 48 49 50
 * Event handlers can be anything which implement the Callable concept
 * (http://en.cppreference.com/w/cpp/concept/Callable)
 * libvlcpp can take ownership (ie. move it to an internal storage) of your handler.
 * If you provide a rvalue, libvlcpp will store a reference to the handler.
 * If you provide a lvalue, libvlcpp will move the handler internaly.
51 52
 */
class EventManager : public Internal<libvlc_event_manager_t>
53
{
54 55 56 57
protected:
    template <typename T>
    using DecayPtr = typename std::add_pointer<typename std::decay<T>::type>::type;

58 59 60 61 62
private:
    // Polymorphic base to hold a templated implementation
    struct EventHandlerBase
    {
        using Wrapper = std::add_pointer<void(const libvlc_event_t*, void*)>::type;
63 64 65 66 67 68
        virtual ~EventHandlerBase() = default;
        /**
         * @brief unregister Unregister this event handler.
         *
         * Calling this method makes the instance invalid.
         */
69
        virtual void unregister() = 0;
70 71
    };

72
    template <typename Func>
73 74
    class EventHandler : public EventHandlerBase
    {
75
    public:
76 77 78 79 80 81 82
        // We have to re-declare a template type, otherwise userCallback wouldn't be a forwarding reference
        // Not doing so works since EventHandler is instantiated with a perfect forwarded type, so Func type
        // will be a reference-less type if the callback was an lvalue, and an lvalue if the callback was an lvalue
        // As described here: http://stackoverflow.com/questions/24497311/is-this-a-universal-reference-does-stdforward-make-sense-here
        // this would still make sense, in a perverted kind of way.
        template <typename FuncTpl>
        EventHandler(EventManager& em, libvlc_event_e eventType, FuncTpl&& userCallback, Wrapper wrapper)
83
            : m_userCallback( std::forward<Func>(userCallback) )
84 85 86 87
            , m_eventManager(&em)
            , m_wrapper(wrapper)
            , m_eventType( eventType )
        {
88 89
            static_assert(std::is_same<typename std::decay<Func>::type,
                                        typename std::decay<FuncTpl>::type>::value, "");
90 91 92 93 94 95
            if (libvlc_event_attach( *m_eventManager, m_eventType, m_wrapper, &m_userCallback ) != 0)
                throw std::bad_alloc();
        }

        ~EventHandler()
        {
96 97
            // We unregister only when the object actually goes out of scope, IE. when it is
            // removed from EventManager's event handler vector
98 99 100
            libvlc_event_detach( *m_eventManager, m_eventType, m_wrapper, &m_userCallback );
        }

101 102
        virtual void unregister() override
        {
103
            m_eventManager->unregister(this);
104 105
        }

106
        EventHandler(const EventHandler&) = delete;
107
        EventHandler& operator=( const EventHandler& ) = delete;
108 109

    private:
110
        // Deduced type is Func& in case of lvalue; Func in case of rvalue.
111
        Func m_userCallback;
112 113 114 115 116 117
        // EventManager always outlive EventHandler, no need for smart pointer
        EventManager* m_eventManager;
        Wrapper m_wrapper;
        libvlc_event_e m_eventType;
    };

118 119 120 121
private:
    // variadic template recursion termination
    void unregister(){}

122
public:
123
    template <typename T, typename... Args>
124
    void unregister(const T e, const Args... args)
125
    {
126
        static_assert(std::is_convertible<decltype(e), const EventHandlerBase*>::value, "Expected const RegisteredEvent");
127 128 129

        {
            auto it = std::find_if(begin(m_lambdas), end(m_lambdas), [&e](decltype(m_lambdas)::value_type &value) {
130
                return e == value.get();
131 132 133 134 135 136
            });
            if (it != end(m_lambdas))
                m_lambdas.erase( it );
        }

        unregister(args...);
137 138
    }

139 140 141 142 143 144
protected:
    EventManager(InternalPtr ptr)
        : Internal{ ptr, [](InternalPtr){ /* No-op; EventManager's are handled by their respective objects */ } }
    {
    }

145
public:
146 147 148 149 150 151 152 153
    /**
     * @brief EventManager Wraps the same EventManager
     *
     * This will copy the underlying libvlc_event_manager_t, but will not copy
     * the already registered events.
     * This allows you to copy an event manager, register a few events for a
     * punctual task, and unregister those events by destroying the new instance.
     */
154 155 156
    EventManager(const EventManager& em)
        : Internal( em )
    {
157 158
        // Don't rely on the default implementation, as we don't want to copy the
        // current list of events.
159 160
    }

161 162 163 164 165 166 167 168
    /**
     * @brief operator= Wraps the same EventManager
     *
     * This will copy the underlying libvlc_event_manager_t, but will not copy
     * the already registered events.
     * This allows you to copy an event manager, register a few events for a
     * punctual task, and unregister those events by destroying the new instance.
     */
169 170
    EventManager& operator=(const EventManager& em)
    {
171
        // See above notes, this isn't the same as the default assignment operator
172 173
        if (this == &em)
            return *this;
174 175 176 177
        Internal::operator=(em);
        return *this;
    }

178
#if !defined(_MSC_VER) || _MSC_VER >= 1900
179 180
    EventManager(EventManager&&) = default;
    EventManager& operator=(EventManager&&) = default;
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
#else
    EventManager(EventManager&& em)
        : Internal( std::move( em ) )
        , m_lambdas(std::move( em.m_lambdas ) )
    {
    }

    EventManager& operator=(EventManager&& em)
    {
        if ( this == &em )
            return *this;
        Internal::operator=( std::move( em ) );
        m_lambdas = std::move( em.m_lambdas );
    }
#endif
196

197
    using RegisteredEvent = EventHandlerBase*;
198

199 200
protected:

201 202 203 204 205 206 207 208
    /**
     * @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)
209
     * @return              A pointer to an abstract EventHandler type. It is assumed that the EventManager will
210 211 212
     *                      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.
213
     *                      When calling unregister() on this object, the pointer should immediatly be considered invalid.
214
     */
215
    template <typename Func>
216
    RegisteredEvent handle(libvlc_event_e eventType, Func&& f, EventHandlerBase::Wrapper wrapper)
217
    {
218 219 220 221
        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 ) );
222
        return raw;
223 224
    }

225
    template <typename Func>
226
    RegisteredEvent handle(libvlc_event_e eventType, Func&& f)
227
    {
228 229
        EXPECT_SIGNATURE(void());
        return handle(eventType, std::forward<Func>( f ), [](const libvlc_event_t*, void* data)
230
        {
231
            auto callback = static_cast<DecayPtr<Func>>( data );
232 233 234 235 236 237 238
            (*callback)();
        });
    }

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
239
    std::vector<std::unique_ptr<EventHandlerBase>> m_lambdas;
240 241
};

242 243 244
/**
 * @brief The MediaEventManager class allows one to register Media related events
 */
245
class MediaEventManager : public EventManager
246 247
{
    public:
248
        MediaEventManager(InternalPtr ptr) : EventManager( ptr ) {}
249

250
        /**
251 252
         * @brief onMetaChanged Registers an event called when a Media meta changes
         * @param f A std::function<void(libvlc_meta_t)> (or an equivalent Callable type)
253 254
         */
        template <typename Func>
255
        RegisteredEvent onMetaChanged( Func&& f)
256
        {
257 258
            EXPECT_SIGNATURE(void(libvlc_meta_t));
            return handle( libvlc_MediaMetaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
259
            {
260
                auto callback = static_cast<DecayPtr<Func>>(data);
261 262 263
                (*callback)( e->u.media_meta_changed.meta_type );
            });
        }
264

265
        /**
266 267
         * @brief onSubItemAdded Registers an event called when a Media gets a subitem added
         * @param f A std::function<void(MediaPtr)> (or an equivalent Callable type)
268 269
         */
        template <typename Func>
270
        RegisteredEvent onSubItemAdded( Func&& f )
271
        {
272 273
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaSubItemAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
274
            {
275
                auto callback = static_cast<DecayPtr<Func>>(data);
276 277
                auto media = e->u.media_subitem_added.new_child;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
278 279 280
            });
        }

281 282 283 284
        /**
         * \brief onDurationChanged Registers an event called when a media duration changes
         * \param f A std::function<void(int64_t)> (or an equivalent Callable type)
         */
285
        template <typename Func>
286
        RegisteredEvent onDurationChanged( Func&& f )
287
        {
288 289
            EXPECT_SIGNATURE(void(int64_t));
            return handle(libvlc_MediaDurationChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
290
            {
291
                auto callback = static_cast<DecayPtr<Func>>(data);
292 293 294 295
                (*callback)( e->u.media_duration_changed.new_duration );
            });
        }

296 297 298 299 300
        /**
         * \brief onParsedChanged Registers an event called when the preparsed state changes
         * \param f A std::function<void(bool)> (or an equivalent Callable type)
         *          The provided boolean will be true if the media has been parsed, false otherwise.
         */
301
        template <typename Func>
302
        RegisteredEvent onParsedChanged( Func&& f )
303
        {
304 305
            EXPECT_SIGNATURE(void(bool));
            return handle( libvlc_MediaParsedChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
306
            {
307
                auto callback = static_cast<DecayPtr<Func>>(data);
308 309 310 311
                (*callback)( e->u.media_parsed_changed.new_status );
            });
        }

312 313 314 315 316 317 318 319
        /**
         * \brief onFreed Registers an event called when the media reaches a refcount of 0
         * \param f A std::function<void(MediaPtr)> (or an equivalent Callable type)
         *          The media is being destroyed by libvlc when this event gets called.
         *          Any Media instance that would live past this call would wrap
         *          a dangling pointer.
         *
         */
320
        template <typename Func>
321
        RegisteredEvent onFreed( Func&& f)
322
        {
323
            //FIXME: Provide a read-only Media wrapper, to avoid wild dangling references to appear.
324 325
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaFreed, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
326
            {
327
                auto callback = static_cast<DecayPtr<Func>>(data);
328 329
                auto media = e->u.media_freed.md;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
330 331 332
            });
        }

333 334 335 336
        /**
         * \brief onStateChanged Registers an event called when the Media state changes
         * \param f A std::function<void(libvlc_state_t)> (or an equivalent Callable type)
         */
337
        template <typename Func>
338
        RegisteredEvent onStateChanged( Func&& f)
339
        {
340
            //FIXME: Wrap libvlc_state_t in a class enum
341 342
            EXPECT_SIGNATURE(void(libvlc_state_t));
            return handle(libvlc_MediaStateChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
343
            {
344
                auto callback = static_cast<DecayPtr<Func>>(data);
345 346 347 348
                (*callback)( e->u.media_state_changed.new_state );
            });
        }

349 350 351 352 353 354
        /**
         * \brief onSubItemTreeAdded Registers an event called when all subitem have been added.
         * \param f A std::function<void(MediaPtr)> (or an equivalent Callable type)
         *          The provided Media is the media for which this event has been registered,
         *          not a potential child media
         */
355
        template <typename Func>
356
        RegisteredEvent onSubItemTreeAdded( Func&& f)
357
        {
358
            EXPECT_SIGNATURE(void(MediaPtr));
359
            return handle(libvlc_MediaSubItemTreeAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
360
            {
361
                auto callback = static_cast<DecayPtr<Func>>(data);
362 363
                auto media = e->u.media_subitemtree_added.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
364 365
            });
        }
366 367
};

368 369 370
/**
 * @brief The MediaPlayerEventManager class allows one to register MediaPlayer related events
 */
371
class MediaPlayerEventManager : public EventManager
372 373
{
    public:
374 375
        MediaPlayerEventManager(InternalPtr ptr) : EventManager( ptr ) {}

376 377 378 379
        /**
         * \brief onMediaChanged Registers an event called when the played media changes
         * \param f A std::function<void(MediaPtr)> (or an equivalent Callable type)
         */
380
        template <typename Func>
381
        RegisteredEvent onMediaChanged( Func&& f )
382
        {
383 384
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaPlayerMediaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
385
            {
386
                auto callback = static_cast<DecayPtr<Func>>( data );
387 388
                auto media = e->u.media_player_media_changed.new_media;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
389 390
            });
        }
391 392

        template <typename Func>
393
        RegisteredEvent onNothingSpecial( Func&& f )
394
        {
395
            return handle(libvlc_MediaPlayerNothingSpecial, std::forward<Func>( f ));
396 397
        }

398 399 400 401
        /**
         * \brief onOpening Registers an event called when the MediaPlayer starts initializing
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
402
        template <typename Func>
403
        RegisteredEvent onOpening( Func&& f )
404
        {
405
            return handle(libvlc_MediaPlayerOpening, std::forward<Func>( f ) );
406 407
        }

408 409 410 411 412
        /**
         * \brief onBuffering Registers an event called when the buffering state changes
         * \param f A std::function<void(float)> (or an equivalent Callable type)
         *          The provided float is the current media buffering percentage
         */
413
        template <typename Func>
414
        RegisteredEvent onBuffering( Func&& f )
415
        {
416 417 418 419 420 421
            EXPECT_SIGNATURE(void(float));
            return handle(libvlc_MediaPlayerBuffering, std::forward<Func>(f), [](const libvlc_event_t* e, void* data)
            {
                auto callback = static_cast<DecayPtr<Func>>( data );
                (*callback)( e->u.media_player_buffering.new_cache );
            });
422 423
        }

424 425 426 427
        /**
         * \brief onPlaying Registers an event called when the media player reaches playing state
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
428
        template <typename Func>
429
        RegisteredEvent onPlaying( Func&& f )
430
        {
431
            return handle( libvlc_MediaPlayerPlaying, std::forward<Func>( f ) );
432 433
        }

434 435 436 437
        /**
         * \brief onPaused Registers an event called when the media player gets paused
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
438
        template <typename Func>
439
        RegisteredEvent onPaused(Func&& f)
440
        {
441
            return handle( libvlc_MediaPlayerPaused, std::forward<Func>( f ) );
442 443
        }

444 445 446 447
        /**
         * \brief onStopped Registers an event called when the media player gets stopped
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
448
        template <typename Func>
449
        RegisteredEvent onStopped(Func&& f)
450
        {
451
            return handle( libvlc_MediaPlayerStopped, std::forward<Func>( f ) );
452 453
        }

454
        // This never gets invoked
455
        template <typename Func>
456
        RegisteredEvent onForward(Func&& f)
457
        {
458
            return handle( libvlc_MediaPlayerForward, std::forward<Func>( f ) );
459 460
        }

461
        // This never gets invoked.
462
        template <typename Func>
463
        RegisteredEvent onBackward(Func&& f)
464
        {
465
            return handle( libvlc_MediaPlayerBackward, std::forward<Func>( f ) );
466 467
        }

468 469 470 471
        /**
         * \brief onEndReached Registers an event called when the media player reaches the end of a media
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
472
        template <typename Func>
473
        RegisteredEvent onEndReached(Func&& f)
474
        {
475
            return handle( libvlc_MediaPlayerEndReached, std::forward<Func>( f ) );
476 477
        }

478 479 480 481
        /**
         * \brief onEncounteredError Registers an event called when the media player reaches encounters an error
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
482
        template <typename Func>
483
        RegisteredEvent onEncounteredError(Func&& f)
484
        {
485
            return handle( libvlc_MediaPlayerEncounteredError, std::forward<Func>( f ) );
486 487
        }

488 489 490 491 492
        /**
         * \brief onTimeChanged Registers an event called periodically to indicate the current playback time
         * \param f A std::function<void(int64_t)> (or an equivalent Callable type)
         *          Time is in ms.
         */
493
        template <typename Func>
494
        RegisteredEvent onTimeChanged( Func&& f )
495
        {
496 497
            EXPECT_SIGNATURE(void(libvlc_time_t));
            return handle( libvlc_MediaPlayerTimeChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
498
            {
499
                auto callback = static_cast<DecayPtr<Func>>( data );
500 501 502 503
                (*callback)( e->u.media_player_time_changed.new_time );
            });
        }

504 505 506 507 508
        /**
         * \brief onPositionChanged Registers an event called periodically to indicate the current playback position.
         * \param f A std::function<void(float)> (or an equivalent Callable type)
         *          Provided float in a number between 0 (beginning of the media) and 1 (end of the media)
         */
509
        template <typename Func>
510
        RegisteredEvent onPositionChanged( Func&& f )
511
        {
512 513
            EXPECT_SIGNATURE(void(float));
            return handle( libvlc_MediaPlayerPositionChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
514
            {
515
                auto callback = static_cast<DecayPtr<Func>>( data );
516 517 518 519
                (*callback)( e->u.media_player_position_changed.new_position );
            });
        }

520 521 522 523 524
        /**
         * \brief onSeekableChanged Registers an event called when the seekable state changes
         * \param f A std::function<void(bool)> (or an equivalent Callable type)
         *          The provided boolean will be true if the media is seekable, false otherwise.
         */
525
        template <typename Func>
526
        RegisteredEvent onSeekableChanged( Func&& f )
527
        {
528 529
            EXPECT_SIGNATURE(void(bool));
            return handle( libvlc_MediaPlayerSeekableChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
530
            {
531
                auto callback = static_cast<DecayPtr<Func>>( data );
532
                (*callback)( e->u.media_player_seekable_changed.new_seekable != 0 );
533 534 535
            });
        }

536 537 538 539 540
        /**
         * \brief onPausableChanged Registers an event called when the pausable state changes
         * \param f A std::function<void(bool)> (or an equivalent Callable type)
         *          The provided boolean will be true if the playback can be paused, false otherwise.
         */
541
        template <typename Func>
542
        RegisteredEvent onPausableChanged( Func&& f )
543
        {
544 545
            EXPECT_SIGNATURE(void(bool));
            return handle( libvlc_MediaPlayerSeekableChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
546
            {
547
                auto callback = static_cast<DecayPtr<Func>>( data );
548
                (*callback)( e->u.media_player_seekable_changed.new_seekable != 0 );
549 550 551
            });
        }

552 553 554 555 556 557 558
        /**
         * \brief onTitleChanged Registers an event called when the current title changes
         * \param f A std::function<void(int)> (or an equivalent Callable type)
         *          The provided integer is the new current title identifier.
         *          Please note that this has nothing to do with a text title (the name of
         *          the video being played, for instance)
         */
559
        template <typename Func>
560
        RegisteredEvent onTitleChanged( Func&& f )
561
        {
562 563
            EXPECT_SIGNATURE(void(int));
            return handle( libvlc_MediaPlayerTitleChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
564
            {
565
                auto callback = static_cast<DecayPtr<Func>>( data );
566 567 568 569
                (*callback)( e->u.media_player_title_changed.new_title );
            });
        }

570 571 572 573 574
        /**
         * \brief onSnapshotTaken Registers an event called when a snapshot gets taken
         * \param f A std::function<void(std::string)> (or an equivalent Callable type)
         *          The provided string is the path of the created snapshot
         */
575
        template <typename Func>
576
        RegisteredEvent onSnapshotTaken( Func&& f )
577
        {
578 579
            EXPECT_SIGNATURE(void(std::string));
            return handle( libvlc_MediaPlayerSnapshotTaken, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
580
            {
581
                auto callback = static_cast<DecayPtr<Func>>( data );
582 583 584 585
                (*callback)( e->u.media_player_snapshot_taken.psz_filename );
            });
        }

586 587 588 589
        /**
         * \brief onLengthChanged Registers an event called when the length gets updated.
         * \param f A std::function<void(int64_t)> (or an equivalent Callable type)
         */
590
        template <typename Func>
591
        RegisteredEvent onLengthChanged( Func&& f )
592
        {
593 594
            EXPECT_SIGNATURE(void(libvlc_time_t));
            return handle( libvlc_MediaPlayerLengthChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
595
            {
596
                auto callback = static_cast<DecayPtr<Func>>( data );
597 598 599 600
                (*callback)( e->u.media_player_length_changed.new_length );
            });
        }

601 602 603 604 605
        /**
         * \brief onVout Registers an event called when the number of vout changes
         * \param f A std::function<void(int)> (or an equivalent Callable type)
         *          The provided int represents the number of currently available vout.
         */
606
        template <typename Func>
607
        RegisteredEvent onVout( Func&& f )
608
        {
609 610
            EXPECT_SIGNATURE(void(int));
            return handle( libvlc_MediaPlayerVout, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
611
            {
612
                auto callback = static_cast<DecayPtr<Func>>( data );
613 614 615 616
                (*callback)( e->u.media_player_vout.new_count );
            });
        }

617 618 619 620 621
        /**
         * \brief onScrambledChanged Registers an event called when the scrambled state changes
         * \param f A std::function<void(bool)> (or an equivalent Callable type)
         *          The provided boolean will be true if the media is scrambled, false otherwise.
         */
622
        template <typename Func>
623
        RegisteredEvent onScrambledChanged( Func&& f )
624
        {
625
            EXPECT_SIGNATURE(void(bool));
626
            return handle( libvlc_MediaPlayerScrambledChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
627
            {
628
                auto callback = static_cast<DecayPtr<Func>>( data );
629
                (*callback)( e->u.media_player_scrambled_changed.new_scrambled != 0 );
630 631 632
            });
        }

633
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
634 635 636 637 638 639
        /**
         * \brief onESAdded Registers an event called when an elementary stream get added
         * \param f A std::function<void(libvlc_track_type_t, int)> (or an equivalent Callable type)
         *          libvlc_track_type_t: The new track type
         *          int: the new track index
         */
640
        template <typename Func>
641
        RegisteredEvent onESAdded( Func&& f )
642
        {
643
            //FIXME: Expose libvlc_track_type_t as an enum class
644 645
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
646
            {
647
                auto callback = static_cast<DecayPtr<Func>>( data );
648 649 650 651
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }

652 653 654 655 656 657
        /**
         * \brief onESDeleted Registers an event called when an elementary stream get deleted
         * \param f A std::function<void(libvlc_track_type_t, int)> (or an equivalent Callable type)
         *          libvlc_track_type_t: The track type
         *          int: the track index
         */
658
        template <typename Func>
659
        RegisteredEvent onESDeleted( Func&& f )
660
        {
661 662
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESDeleted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
663
            {
664
                auto callback = static_cast<DecayPtr<Func>>( data );
665 666 667 668
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }

669 670 671 672 673 674
        /**
         * \brief onESSelected Registers an event called when an elementary stream get selected
         * \param f A std::function<void(libvlc_track_type_t, int)> (or an equivalent Callable type)
         *          libvlc_track_type_t: The track type
         *          int: the track index
         */
675
        template <typename Func>
676
        RegisteredEvent onESSelected( Func&& f )
677
        {
678 679
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESSelected, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
680
            {
681
                auto callback = static_cast<DecayPtr<Func>>( data );
682 683 684
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }
685
#endif
686 687
};

688 689 690
/**
 * @brief The MediaListEventManager class allows one to register MediaList related events
 */
691
class MediaListEventManager : public EventManager
692 693
{
    public:
694 695
        MediaListEventManager(InternalPtr ptr) : EventManager( ptr ) {}

696 697 698 699 700 701
        /**
         * \brief onItemAdded Registers an event called when an item gets added to the media list
         * \param f A std::function<void(MediaPtr, int)> (or an equivalent Callable type)
         *          MediaPtr: The added media
         *          int: The media index in the list
         */
702
        template <typename Func>
703
        RegisteredEvent onItemAdded( Func&& f )
704
        {
705 706
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListItemAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
707
            {
708
                auto callback = static_cast<DecayPtr<Func>>( data );
709 710 711
                auto media = e->u.media_list_item_added.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr,
                             e->u.media_list_item_added.index );
712 713 714
            });
        }

715 716 717 718 719 720
        /**
         * \brief onWillAddItem Registers an event called when an item is about to be added to the media list
         * \param f A std::function<void(MediaPtr, int)> (or an equivalent Callable type)
         *          MediaPtr: The added media
         *          int: The media index in the list
         */
721
        template <typename Func>
722
        RegisteredEvent onWillAddItem( Func&& f )
723
        {
724 725
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle( libvlc_MediaListWillAddItem, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
726
            {
727
                auto callback = static_cast<DecayPtr<Func>>( data );
728 729 730
                auto media = e->u.media_list_will_add_item.item;
                (*callback)(media != nullptr ? std::make_shared<Media>( media, true ) : nullptr,
                            e->u.media_list_will_add_item.index );
731 732 733
            });
        }

734 735 736 737 738 739
        /**
         * \brief onItemDeleted Registers an event called when an item gets deleted to the media list
         * \param f A std::function<void(MediaPtr, int)> (or an equivalent Callable type)
         *          MediaPtr: The added media
         *          int: The media index in the list
         */
740
        template <typename Func>
741
        RegisteredEvent onItemDeleted( Func&& f )
742
        {
743 744
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListItemDeleted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
745
            {
746
                auto callback = static_cast<DecayPtr<Func>>( data );
747 748 749
                auto media = e->u.media_list_item_deleted.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr,
                             e->u.media_list_item_deleted.index );
750 751 752
            });
        }

753 754 755 756 757 758
        /**
         * \brief onWillDeleteItem Registers an event called when an item is about to be deleted
         * \param f A std::function<void(MediaPtr, int)> (or an equivalent Callable type)
         *          MediaPtr: The added media
         *          int: The media index in the list
         */
759
        template <typename Func>
760
        RegisteredEvent onWillDeleteItem( Func&& f )
761
        {
762 763
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListWillDeleteItem, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
764
            {
765
                auto callback = static_cast<DecayPtr<Func>>( data );
766 767 768
                auto media = e->u.media_list_will_delete_item.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr,
                             e->u.media_list_will_delete_item.index );
769 770
            });
        }
771 772
};

773 774 775 776
/**
 * @brief The MediaListPlayerEventManager class
 * Those events aren't sent by VLC so far.
 */
777
class MediaListPlayerEventManager : public EventManager
778 779
{
    public:
780 781
        MediaListPlayerEventManager(InternalPtr ptr) : EventManager( ptr ) {}

782
        template <typename Func>
783
        RegisteredEvent onPlayed(Func&& f)
784
        {
785
            return handle(libvlc_MediaListPlayerPlayed, std::forward<Func>( f ) );
786 787
        }

788
        template <typename Func>
789
        RegisteredEvent onNextItemSet( Func&& f )
790
        {
791 792
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaListPlayerNextItemSet, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
793
            {
794
                auto callback = static_cast<DecayPtr<Func>>( data );
795 796
                auto media = e->u.media_list_player_next_item_set.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
797
            });
798 799
        }

800
        template <typename Func>
801
        RegisteredEvent onStopped( Func&& f )
802
        {
803
            return handle(libvlc_MediaListPlayerStopped, std::forward<Func>( f ) );
804
        }
805
};
806

807 808 809
/**
 * @brief The MediaDiscovererEventManager class allows one to register MediaDiscoverer related events
 */
810 811 812 813 814
class MediaDiscovererEventManager : public EventManager
{
    public:
        MediaDiscovererEventManager(InternalPtr ptr) : EventManager( ptr ) {}

815 816 817 818
        /**
         * \brief onStarted Registers an event called when the discovery starts
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
819
        template <typename Func>
820
        RegisteredEvent onStarted(Func&& f)
821
        {
822
            return handle(libvlc_MediaDiscovererStarted, std::forward<Func>( f ) );
823 824
        }

825 826 827 828
        /**
         * \brief onStopped Registers an event called when the discovery stops
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
829
        template <typename Func>
830
        RegisteredEvent onStopped(Func&& f)
831
        {
832
            return handle(libvlc_MediaDiscovererEnded, std::forward<Func>( f ) );
833
        }
834
};
835

836 837 838
/**
 * @brief The VLMEventManager class allows one to register VLM related events
 */
839 840 841
class VLMEventManager : public EventManager
{
    public:
842
        VLMEventManager(InternalPtr ptr) : EventManager(ptr) {}
843

844 845 846 847 848
        /**
         * \brief onMediaAdded Registers an event called when a media gets added
         * \param f A std::function<void(std::string)> (or an equivalent Callable type)
         *          The given string is the name of the added media
         */
849
        template <typename Func>
850
        RegisteredEvent onMediaAdded( Func&& f )
851
        {
852 853
            EXPECT_SIGNATURE(void(std::string));
            return handle(libvlc_VlmMediaAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
854
            {
855
                auto callback = static_cast<DecayPtr<Func>>( data );
856 857
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "" );
            });
858 859
        }

860 861 862 863 864
        /**
         * \brief onMediaRemoved Registers an event called when a media gets removed
         * \param f A std::function<void(std::string)> (or an equivalent Callable type)
         *          The given string is the name of the removed media
         */
865
        template <typename Func>
866
        RegisteredEvent onMediaRemoved( Func&& f )
867
        {
868 869
            EXPECT_SIGNATURE(void(std::string));
            return handle(libvlc_VlmMediaRemoved, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
870
            {
871
                auto callback = static_cast<DecayPtr<Func>>( data );
872 873
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "" );
            });
874 875
        }

876 877 878 879 880
        /**
         * \brief onMediaChanged Registers an event called when a media changes
         * \param f A std::function<void(std::string)> (or an equivalent Callable type)
         *          The given string is the name of the changed media
         */
881
        template <typename Func>
882
        RegisteredEvent onMediaChanged( Func&& f )
883
        {
884 885
            EXPECT_SIGNATURE(void(std::string));
            return handle(libvlc_VlmMediaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
886
            {
887
                auto callback = static_cast<DecayPtr<Func>>( data );
888 889 890
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "" );
            });
        }
891

892 893 894 895 896 897 898
        /**
         * \brief onMediaInstanceStarted Registers an event called when a media instance starts
         * \param f A std::function<void(std::string, std::string)> (or an equivalent Callable type)
         *          Parameters are:
         *              - The media name
         *              - The instance name
         */
899
        template <typename Func>
900
        RegisteredEvent onMediaInstanceStarted( Func&& f )
901
        {
902 903
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStarted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
904
            {
905
                auto callback = static_cast<DecayPtr<Func>>( data );
906 907 908
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "",
                             e->u.vlm_media_event.psz_instance_name ? e->u.vlm_media_event.psz_instance_name : "" );
            });
909 910
        }

911 912 913 914 915 916 917
        /**
         * \brief onMediaInstanceStopped Registers an event called when a media instance stops
         * \param f A std::function<void(std::string, std::string)> (or an equivalent Callable type)
         *          Parameters are:
         *              - The media name
         *              - The instance name
         */
918
        template <typename Func>
919
        RegisteredEvent onMediaInstanceStopped( Func&& f )
920
        {
921 922
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStopped, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
923
            {
924
                auto callback = static_cast<DecayPtr<Func>>( data );
925 926 927
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "",
                             e->u.vlm_media_event.psz_instance_name ? e->u.vlm_media_event.psz_instance_name : "" );
            });
928 929
        }

930 931 932 933 934 935 936
        /**
         * \brief onMediaInstanceStatusInit Registers an event called when a media instance is initializing
         * \param f A std::function<void(std::string, std::string)> (or an equivalent Callable type)
         *          Parameters are:
         *              - The media name
         *              - The instance name
         */
937
        template <typename Func>
938
        RegisteredEvent onMediaInstanceStatusInit( Func&& f )
939
        {
940 941
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStatusInit, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
942
            {
943
                auto callback = static_cast<DecayPtr<Func>>( data );
944 945 946
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "",
                             e->u.vlm_media_event.psz_instance_name ? e->u.vlm_media_event.psz_instance_name : "" );
            });
947 948
        }

949 950 951 952 953 954 955
        /**
         * \brief onMediaInstanceStatusOpening Registers an event called when a media instance is opening
         * \param f A std::function<void(std::string, std::string)> (or an equivalent Callable type)
         *          Parameters are:
         *              - The media name
         *              - The instance name
         */
956
        template <typename Func>
957
        RegisteredEvent onMediaInstanceStatusOpening( Func&& f )
958
        {
959 960
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStatusOpening, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
961
            {
962
                auto callback = static_cast<DecayPtr<Func>>( data );
963 964 965
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "",
                             e->u.vlm_media_event.psz_instance_name ? e->u.vlm_media_event.psz_instance_name : "" );
            });
966 967
        }

968 969 970 971 972 973 974
        /**
         * \brief onMediaInstanceStatusPlaying Registers an event called when a media instance reaches playing state
         * \param f A std::function<void(std::string, std::string)> (or an equivalent Callable type)
         *          Parameters are:
         *              - The media name
         *              - The instance name
         */
975
        template <typename Func>
976
        RegisteredEvent onMediaInstanceStatusPlaying( Func&& f )
977
        {
978 979
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStatusPlaying, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
980
            {
981
                auto callback = static_cast<DecayPtr<Func>>( data );
982 983 984
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "",
                             e->u.vlm_media_event.psz_instance_name ? e->u.vlm_media_event.psz_instance_name : "" );
            });
985 986
        }

987 988 989 990 991 992 993
        /**
         * \brief onMediaInstanceStatusPause Registers an event called when a media instance gets paused
         * \param f A std::function<void(std::string, std::string)> (or an equivalent Callable type)
         *          Parameters are:
         *              - The media name
         *              - The instance name
         */
994
        template <typename Func>
995
        RegisteredEvent onMediaInstanceStatusPause( Func&& f )
996
        {
997 998
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStatusPause, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
999
            {
1000
                auto callback = static_cast<DecayPtr<Func>>( data );
1001 1002 1003
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "",
                             e->u.vlm_media_event.psz_instance_name ? e->u.vlm_media_event.psz_instance_name : "" );
            });
1004
        }
1005

1006 1007 1008 1009 1010 1011 1012
        /**
         * \brief onMediaInstanceStatusEnd Registers an event called when a media instance ends
         * \param f A std::function<void(std::string, std::string)> (or an equivalent Callable type)
         *          Parameters are:
         *              - The media name
         *              - The instance name
         */
1013
        template <typename Func>
1014
        RegisteredEvent onMediaInstanceStatusEnd( Func&& f )
1015
        {
1016 1017
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStatusEnd, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
1018
            {
1019
                auto callback = static_cast<DecayPtr<Func>>( data );
1020 1021 1022
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "",
                             e->u.vlm_media_event.psz_instance_name ? e->u.vlm_media_event.psz_instance_name : "" );
            });
1023
        }
1024

1025 1026 1027 1028 1029 1030 1031
        /**
         * \brief onMediaInstanceStatusError Registers an event called when a media instance encouters an error
         * \param f A std::function<void(std::string, std::string)> (or an equivalent Callable type)
         *          Parameters are:
         *              - The media name
         *              - The instance name
         */
1032
        template <typename Func>
1033
        RegisteredEvent onMediaInstanceStatusError( Func&& f )
1034
        {
1035 1036
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStatusError, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
1037
            {
1038
                auto callback = static_cast<DecayPtr<Func>>( data );
1039 1040 1041 1042 1043
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "",
                             e->u.vlm_media_event.psz_instance_name ? e->u.vlm_media_event.psz_instance_name : "" );
            });
        }
};
1044 1045 1046
}

#endif // LIBVLC_EVENTMANAGER_HPP