EventManager.hpp 48.7 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
#include "Media.hpp"
31

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

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

39 40 41
namespace VLC
{

42 43 44
/**
 * @brief This class serves as a base for all event managers.
 *
45 46 47
 * All events can be handled by providing a std::function.
 * libvlcpp will take ownership (ie. the function will be moved inside an internal list)
 * If the provided std::function is a lambda, it may capture anything you desire
48 49
 */
class EventManager : public Internal<libvlc_event_manager_t>
50
{
51 52 53 54
protected:
    template <typename T>
    using DecayPtr = typename std::add_pointer<typename std::decay<T>::type>::type;

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

69
    template <typename Func>
70 71
    class EventHandler : public EventHandlerBase
    {
72
    public:
73 74 75 76 77 78 79
        // 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)
80
            : m_userCallback( std::forward<Func>(userCallback) )
81 82 83 84
            , m_eventManager(&em)
            , m_wrapper(wrapper)
            , m_eventType( eventType )
        {
85 86
            static_assert(std::is_same<typename std::decay<Func>::type,
                                        typename std::decay<FuncTpl>::type>::value, "");
87 88 89 90 91 92
            if (libvlc_event_attach( *m_eventManager, m_eventType, m_wrapper, &m_userCallback ) != 0)
                throw std::bad_alloc();
        }

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

98 99
        virtual void unregister() override
        {
100
            m_eventManager->unregister(this);
101 102
        }

103
        EventHandler(const EventHandler&) = delete;
104
        EventHandler& operator=( const EventHandler& ) = delete;
105 106

    private:
107
        // Deduced type is Func& in case of lvalue; Func in case of rvalue.
108 109 110
        // We decay the type to ensure we either copy or take ownership.
        // Taking a reference would quite likely lead to unexpected behavior
        typename std::decay<Func>::type m_userCallback;
111 112 113 114 115 116
        // EventManager always outlive EventHandler, no need for smart pointer
        EventManager* m_eventManager;
        Wrapper m_wrapper;
        libvlc_event_e m_eventType;
    };

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

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

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

        unregister(args...);
136 137
    }

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

144
public:
145 146 147 148 149 150 151 152
    /**
     * @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.
     */
153 154 155
    EventManager(const EventManager& em)
        : Internal( em )
    {
156 157
        // Don't rely on the default implementation, as we don't want to copy the
        // current list of events.
158 159
    }

160 161 162 163 164 165 166 167
    /**
     * @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.
     */
168 169
    EventManager& operator=(const EventManager& em)
    {
170
        // See above notes, this isn't the same as the default assignment operator
171 172
        if (this == &em)
            return *this;
173 174 175 176
        Internal::operator=(em);
        return *this;
    }

177
#if !defined(_MSC_VER) || _MSC_VER >= 1900
178 179
    EventManager(EventManager&&) = default;
    EventManager& operator=(EventManager&&) = default;
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
#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
195

196
    using RegisteredEvent = EventHandlerBase*;
197

198 199
protected:

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

224
    template <typename Func>
225
    RegisteredEvent handle(libvlc_event_e eventType, Func&& f)
226
    {
227 228
        EXPECT_SIGNATURE(void());
        return handle(eventType, std::forward<Func>( f ), [](const libvlc_event_t*, void* data)
229
        {
230
            auto callback = static_cast<DecayPtr<Func>>( data );
231 232 233 234 235 236 237
            (*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
238
    std::vector<std::unique_ptr<EventHandlerBase>> m_lambdas;
239 240
};

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

249
        /**
250 251
         * @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)
252 253
         */
        template <typename Func>
254
        RegisteredEvent onMetaChanged( Func&& f)
255
        {
256 257
            EXPECT_SIGNATURE(void(libvlc_meta_t));
            return handle( libvlc_MediaMetaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
258
            {
259
                auto callback = static_cast<DecayPtr<Func>>(data);
260 261 262
                (*callback)( e->u.media_meta_changed.meta_type );
            });
        }
263

264
        /**
265 266
         * @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)
267 268
         */
        template <typename Func>
269
        RegisteredEvent onSubItemAdded( Func&& f )
270
        {
271 272
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaSubItemAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
273
            {
274
                auto callback = static_cast<DecayPtr<Func>>(data);
275 276
                auto media = e->u.media_subitem_added.new_child;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
277 278 279
            });
        }

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

295 296 297 298 299
        /**
         * \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.
         */
300
        template <typename Func>
301
        RegisteredEvent onParsedChanged( Func&& f )
302
        {
303
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
304 305
            EXPECT_SIGNATURE( void(Media::ParsedStatus) );
            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
                (*callback)( static_cast<Media::ParsedStatus>( e->u.media_parsed_changed.new_status ) );
309
            });
310 311 312 313 314 315 316 317
#else
            EXPECT_SIGNATURE( void(bool) );
            return handle(libvlc_MediaParsedChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
            {
                auto callback = static_cast<DecayPtr<Func>>(data);
                (*callback)( bool( e->u.media_parsed_changed.new_status ) );
            });
#endif
318 319
        }

320 321 322 323 324 325 326 327
        /**
         * \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.
         *
         */
328
        template <typename Func>
329
        RegisteredEvent onFreed( Func&& f)
330
        {
331
            //FIXME: Provide a read-only Media wrapper, to avoid wild dangling references to appear.
332 333
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaFreed, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
334
            {
335
                auto callback = static_cast<DecayPtr<Func>>(data);
336 337
                auto media = e->u.media_freed.md;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
338 339 340
            });
        }

341 342 343 344
        /**
         * \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)
         */
345
        template <typename Func>
346
        RegisteredEvent onStateChanged( Func&& f)
347
        {
348
            //FIXME: Wrap libvlc_state_t in a class enum
349 350
            EXPECT_SIGNATURE(void(libvlc_state_t));
            return handle(libvlc_MediaStateChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
351
            {
352
                auto callback = static_cast<DecayPtr<Func>>(data);
353 354 355 356
                (*callback)( e->u.media_state_changed.new_state );
            });
        }

357 358 359 360 361 362
        /**
         * \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
         */
363
        template <typename Func>
364
        RegisteredEvent onSubItemTreeAdded( Func&& f)
365
        {
366
            EXPECT_SIGNATURE(void(MediaPtr));
367
            return handle(libvlc_MediaSubItemTreeAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
368
            {
369
                auto callback = static_cast<DecayPtr<Func>>(data);
370 371
                auto media = e->u.media_subitemtree_added.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
372 373
            });
        }
374 375
};

376 377 378
/**
 * @brief The MediaPlayerEventManager class allows one to register MediaPlayer related events
 */
379
class MediaPlayerEventManager : public EventManager
380 381
{
    public:
382 383
        MediaPlayerEventManager(InternalPtr ptr) : EventManager( ptr ) {}

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

        template <typename Func>
401
        RegisteredEvent onNothingSpecial( Func&& f )
402
        {
403
            return handle(libvlc_MediaPlayerNothingSpecial, std::forward<Func>( f ));
404 405
        }

406 407 408 409
        /**
         * \brief onOpening Registers an event called when the MediaPlayer starts initializing
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
410
        template <typename Func>
411
        RegisteredEvent onOpening( Func&& f )
412
        {
413
            return handle(libvlc_MediaPlayerOpening, std::forward<Func>( f ) );
414 415
        }

416 417 418 419 420
        /**
         * \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
         */
421
        template <typename Func>
422
        RegisteredEvent onBuffering( Func&& f )
423
        {
424 425 426 427 428 429
            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 );
            });
430 431
        }

432 433 434 435
        /**
         * \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)
         */
436
        template <typename Func>
437
        RegisteredEvent onPlaying( Func&& f )
438
        {
439
            return handle( libvlc_MediaPlayerPlaying, std::forward<Func>( f ) );
440 441
        }

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

452 453 454 455
        /**
         * \brief onStopped Registers an event called when the media player gets stopped
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
456
        template <typename Func>
457
        RegisteredEvent onStopped(Func&& f)
458
        {
459
            return handle( libvlc_MediaPlayerStopped, std::forward<Func>( f ) );
460 461
        }

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

469
        // This never gets invoked.
470
        template <typename Func>
471
        RegisteredEvent onBackward(Func&& f)
472
        {
473
            return handle( libvlc_MediaPlayerBackward, std::forward<Func>( f ) );
474 475
        }

476 477 478 479
        /**
         * \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)
         */
480
        template <typename Func>
481
        RegisteredEvent onEndReached(Func&& f)
482
        {
483
            return handle( libvlc_MediaPlayerEndReached, std::forward<Func>( f ) );
484 485
        }

486 487 488 489
        /**
         * \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)
         */
490
        template <typename Func>
491
        RegisteredEvent onEncounteredError(Func&& f)
492
        {
493
            return handle( libvlc_MediaPlayerEncounteredError, std::forward<Func>( f ) );
494 495
        }

496 497 498 499 500
        /**
         * \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.
         */
501
        template <typename Func>
502
        RegisteredEvent onTimeChanged( Func&& f )
503
        {
504 505
            EXPECT_SIGNATURE(void(libvlc_time_t));
            return handle( libvlc_MediaPlayerTimeChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
506
            {
507
                auto callback = static_cast<DecayPtr<Func>>( data );
508 509 510 511
                (*callback)( e->u.media_player_time_changed.new_time );
            });
        }

512 513 514 515 516
        /**
         * \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)
         */
517
        template <typename Func>
518
        RegisteredEvent onPositionChanged( Func&& f )
519
        {
520 521
            EXPECT_SIGNATURE(void(float));
            return handle( libvlc_MediaPlayerPositionChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
522
            {
523
                auto callback = static_cast<DecayPtr<Func>>( data );
524 525 526 527
                (*callback)( e->u.media_player_position_changed.new_position );
            });
        }

528 529 530 531 532
        /**
         * \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.
         */
533
        template <typename Func>
534
        RegisteredEvent onSeekableChanged( Func&& f )
535
        {
536 537
            EXPECT_SIGNATURE(void(bool));
            return handle( libvlc_MediaPlayerSeekableChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
538
            {
539
                auto callback = static_cast<DecayPtr<Func>>( data );
540
                (*callback)( e->u.media_player_seekable_changed.new_seekable != 0 );
541 542 543
            });
        }

544 545 546 547 548
        /**
         * \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.
         */
549
        template <typename Func>
550
        RegisteredEvent onPausableChanged( Func&& f )
551
        {
552 553
            EXPECT_SIGNATURE(void(bool));
            return handle( libvlc_MediaPlayerSeekableChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
554
            {
555
                auto callback = static_cast<DecayPtr<Func>>( data );
556
                (*callback)( e->u.media_player_seekable_changed.new_seekable != 0 );
557 558 559
            });
        }

560 561 562 563 564 565 566
        /**
         * \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)
         */
567
        template <typename Func>
568
        RegisteredEvent onTitleChanged( Func&& f )
569
        {
570 571
            EXPECT_SIGNATURE(void(int));
            return handle( libvlc_MediaPlayerTitleChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
572
            {
573
                auto callback = static_cast<DecayPtr<Func>>( data );
574 575 576 577
                (*callback)( e->u.media_player_title_changed.new_title );
            });
        }

578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
        /**
         * \brief onChapterChanged Registers an event called when the current chapter changes
         * \param f A std::function<void(int)> (or an equivalent Callable type)
         *          The provided integer is the new current chapter identifier.
         *          Please note that this has nothing to do with a text chapter (the name of
         *          the video being played, for instance)
         */
        template <typename Func>
        RegisteredEvent onChapterChanged( Func&& f )
        {
            EXPECT_SIGNATURE(void(int));
            return handle( libvlc_MediaPlayerChapterChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
            {
                auto callback = static_cast<DecayPtr<Func>>( data );
                (*callback)( e->u.media_player_chapter_changed.new_chapter );
            });
        }
#endif

598 599 600 601 602
        /**
         * \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
         */
603
        template <typename Func>
604
        RegisteredEvent onSnapshotTaken( Func&& f )
605
        {
606 607
            EXPECT_SIGNATURE(void(std::string));
            return handle( libvlc_MediaPlayerSnapshotTaken, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
608
            {
609
                auto callback = static_cast<DecayPtr<Func>>( data );
610 611 612 613
                (*callback)( e->u.media_player_snapshot_taken.psz_filename );
            });
        }

614 615 616 617
        /**
         * \brief onLengthChanged Registers an event called when the length gets updated.
         * \param f A std::function<void(int64_t)> (or an equivalent Callable type)
         */
618
        template <typename Func>
619
        RegisteredEvent onLengthChanged( Func&& f )
620
        {
621 622
            EXPECT_SIGNATURE(void(libvlc_time_t));
            return handle( libvlc_MediaPlayerLengthChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
623
            {
624
                auto callback = static_cast<DecayPtr<Func>>( data );
625 626 627 628
                (*callback)( e->u.media_player_length_changed.new_length );
            });
        }

629 630 631 632 633
        /**
         * \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.
         */
634
        template <typename Func>
635
        RegisteredEvent onVout( Func&& f )
636
        {
637 638
            EXPECT_SIGNATURE(void(int));
            return handle( libvlc_MediaPlayerVout, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
639
            {
640
                auto callback = static_cast<DecayPtr<Func>>( data );
641 642 643 644
                (*callback)( e->u.media_player_vout.new_count );
            });
        }

645 646 647 648 649
        /**
         * \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.
         */
650
        template <typename Func>
651
        RegisteredEvent onScrambledChanged( Func&& f )
652
        {
653
            EXPECT_SIGNATURE(void(bool));
654
            return handle( libvlc_MediaPlayerScrambledChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
655
            {
656
                auto callback = static_cast<DecayPtr<Func>>( data );
657
                (*callback)( e->u.media_player_scrambled_changed.new_scrambled != 0 );
658 659 660
            });
        }

661
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
662 663 664 665 666 667
        /**
         * \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
         */
668
        template <typename Func>
669
        RegisteredEvent onESAdded( Func&& f )
670
        {
671
            //FIXME: Expose libvlc_track_type_t as an enum class
672 673
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
674
            {
675
                auto callback = static_cast<DecayPtr<Func>>( data );
676 677 678 679
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }

680 681 682 683 684 685
        /**
         * \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
         */
686
        template <typename Func>
687
        RegisteredEvent onESDeleted( Func&& f )
688
        {
689 690
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESDeleted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
691
            {
692
                auto callback = static_cast<DecayPtr<Func>>( data );
693 694 695 696
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }

697 698 699 700 701 702
        /**
         * \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
         */
703
        template <typename Func>
704
        RegisteredEvent onESSelected( Func&& f )
705
        {
706 707
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESSelected, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
708
            {
709
                auto callback = static_cast<DecayPtr<Func>>( data );
710 711 712
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }
713 714 715 716

        /**
         * \brief onAudioDevice Registers an event called when the current audio output device changes
         * \param f A std::function<void(std::string)> (or an equivalent Callable type)
717
         *          The provided string is the new current audio device.
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
         */
        template <typename Func>
        RegisteredEvent onAudioDevice( Func&& f )
        {
            EXPECT_SIGNATURE(void(std::string));
            return handle( libvlc_MediaPlayerAudioDevice, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
            {
                auto callback = static_cast<DecayPtr<Func>>( data );
                (*callback)( e->u.media_player_audio_device.device );
            });
        }
#endif

#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 2, 0)
        /**
         * \brief onCorked Registers an event called when the playback is paused automatically for a higher priority audio stream
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
        template <typename Func>
        RegisteredEvent onCorked( Func&& f )
        {
            return handle( libvlc_MediaPlayerCorked, std::forward<Func>( f ) );
        }

        /**
         * \brief onUncorked Registers an event called when the playback is unpaused automatically after a higher priority audio stream ends
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
        template <typename Func>
        RegisteredEvent onUncorked( Func&& f )
        {
            return handle( libvlc_MediaPlayerUncorked, std::forward<Func>( f ) );
        }

        /**
         * \brief onMuted Registers an event called when the audio is muted
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
        template <typename Func>
        RegisteredEvent onMuted( Func&& f )
        {
            return handle( libvlc_MediaPlayerMuted, std::forward<Func>( f ) );
        }

        /**
         * \brief onUnmuted Registers an event called when the audio is unmuted
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
        template <typename Func>
        RegisteredEvent onUnmuted( Func&& f )
        {
            return handle( libvlc_MediaPlayerUnmuted, std::forward<Func>( f ) );
        }

        /**
         * \brief onAudioVolume Registers an event called when the current audio volume changes
         * \param f A std::function<void(float)> (or an equivalent Callable type)
         *          The provided float is the new current audio volume percentage.
         */
        template <typename Func>
        RegisteredEvent onAudioVolume( Func&& f )
        {
            EXPECT_SIGNATURE(void(float));
            return handle( libvlc_MediaPlayerAudioVolume, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
            {
                auto callback = static_cast<DecayPtr<Func>>( data );
                (*callback)( e->u.media_player_audio_volume.volume );
            });
        }
787
#endif
788 789
};

790 791 792
/**
 * @brief The MediaListEventManager class allows one to register MediaList related events
 */
793
class MediaListEventManager : public EventManager
794 795
{
    public:
796 797
        MediaListEventManager(InternalPtr ptr) : EventManager( ptr ) {}

798 799 800 801 802 803
        /**
         * \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
         */
804
        template <typename Func>
805
        RegisteredEvent onItemAdded( Func&& f )
806
        {
807 808
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListItemAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
809
            {
810
                auto callback = static_cast<DecayPtr<Func>>( data );
811 812 813
                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 );
814 815 816
            });
        }

817 818 819 820 821 822
        /**
         * \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
         */
823
        template <typename Func>
824
        RegisteredEvent onWillAddItem( Func&& f )
825
        {
826 827
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle( libvlc_MediaListWillAddItem, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
828
            {
829
                auto callback = static_cast<DecayPtr<Func>>( data );
830
                auto media = e->u.media_list_will_add_item.item;
831
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr,
832
                            e->u.media_list_will_add_item.index );
833 834 835
            });
        }

836 837 838 839 840 841
        /**
         * \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
         */
842
        template <typename Func>
843
        RegisteredEvent onItemDeleted( Func&& f )
844
        {
845 846
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListItemDeleted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
847
            {
848
                auto callback = static_cast<DecayPtr<Func>>( data );
849 850 851
                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 );
852 853 854
            });
        }

855 856 857 858 859 860
        /**
         * \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
         */
861
        template <typename Func>
862
        RegisteredEvent onWillDeleteItem( Func&& f )
863
        {
864 865
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListWillDeleteItem, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
866
            {
867
                auto callback = static_cast<DecayPtr<Func>>( data );
868 869 870
                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 );
871 872
            });
        }
873

874
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
875 876 877 878 879
        template <typename Func>
        RegisteredEvent onEndReached( Func&& f )
        {
            return handle( libvlc_MediaListEndReached, std::forward<Func>( f ) );
        }
880
#endif
881 882
};

883 884 885 886
/**
 * @brief The MediaListPlayerEventManager class
 * Those events aren't sent by VLC so far.
 */
887
class MediaListPlayerEventManager : public EventManager
888 889
{
    public:
890 891
        MediaListPlayerEventManager(InternalPtr ptr) : EventManager( ptr ) {}

892
        template <typename Func>
893
        RegisteredEvent onPlayed(Func&& f)
894
        {
895
            return handle(libvlc_MediaListPlayerPlayed, std::forward<Func>( f ) );
896 897
        }

898
        template <typename Func>
899
        RegisteredEvent onNextItemSet( Func&& f )
900
        {
901 902
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaListPlayerNextItemSet, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
903
            {
904
                auto callback = static_cast<DecayPtr<Func>>( data );
905 906
                auto media = e->u.media_list_player_next_item_set.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
907
            });
908 909
        }

910
        template <typename Func>
911
        RegisteredEvent onStopped( Func&& f )
912
        {
913
            return handle(libvlc_MediaListPlayerStopped, std::forward<Func>( f ) );
914
        }
915
};
916

917 918 919
/**
 * @brief The MediaDiscovererEventManager class allows one to register MediaDiscoverer related events
 */
920 921 922 923 924
class MediaDiscovererEventManager : public EventManager
{
    public:
        MediaDiscovererEventManager(InternalPtr ptr) : EventManager( ptr ) {}

925 926 927 928
        /**
         * \brief onStarted Registers an event called when the discovery starts
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
929
        template <typename Func>
930
        RegisteredEvent onStarted(Func&& f)
931
        {
932
            return handle(libvlc_MediaDiscovererStarted, std::forward<Func>( f ) );
933 934
        }

935 936 937 938
        /**
         * \brief onStopped Registers an event called when the discovery stops
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
939
        template <typename Func>
940
        RegisteredEvent onStopped(Func&& f)
941
        {
942
            return handle(libvlc_MediaDiscovererEnded, std::forward<Func>( f ) );
943
        }
944
};
945

946 947 948
/**
 * @brief The VLMEventManager class allows one to register VLM related events
 */
949 950 951
class VLMEventManager : public EventManager
{
    public:
952
        VLMEventManager(InternalPtr ptr) : EventManager(ptr) {}
953

954 955 956 957 958
        /**
         * \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
         */
959
        template <typename Func>
960
        RegisteredEvent onMediaAdded( Func&& f )
961
        {
962 963
            EXPECT_SIGNATURE(void(std::string));
            return handle(libvlc_VlmMediaAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
964
            {
965
                auto callback = static_cast<DecayPtr<Func>>( data );
966 967
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "" );
            });
968 969
        }

970 971 972 973 974
        /**
         * \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
         */
975
        template <typename Func>
976
        RegisteredEvent onMediaRemoved( Func&& f )
977
        {
978 979
            EXPECT_SIGNATURE(void(std::string));
            return handle(libvlc_VlmMediaRemoved, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
980
            {
981
                auto callback = static_cast<DecayPtr<Func>>( data );
982 983
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "" );
            });
984 985
        }

986 987 988 989 990
        /**
         * \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
         */
991
        template <typename Func>
992
        RegisteredEvent onMediaChanged( Func&& f )
993
        {
994 995
            EXPECT_SIGNATURE(void(std::string));
            return handle(libvlc_VlmMediaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
996
            {
997
                auto callback = static_cast<DecayPtr<Func>>( data );
998 999 1000
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "" );
            });
        }
1001

1002 1003 1004 1005 1006 1007 1008
        /**
         * \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
         */
1009
        template <typename Func>
1010
        RegisteredEvent onMediaInstanceStarted( Func&& f )
1011
        {
1012 1013
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStarted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
1014
            {
1015
                auto callback = static_cast<DecayPtr<Func>>( data );
1016 1017 1018
                (*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 : "" );
            });
1019 1020
        }

1021 1022 1023 1024 1025 1026 1027
        /**
         * \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
         */
1028
        template <typename Func>
1029
        RegisteredEvent onMediaInstanceStopped( Func&& f )
1030
        {
1031 1032
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStopped, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
1033
            {
1034
                auto callback = static_cast<DecayPtr<Func>>( data );
1035 1036 1037
                (*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 : "" );
            });
1038 1039
        }

1040 1041 1042 1043 1044 1045 1046
        /**
         * \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
         */
1047
        template <typename Func>
1048
        RegisteredEvent onMediaInstanceStatusInit( Func&& f )
1049
        {
1050 1051
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStatusInit, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
1052
            {
1053
                auto callback = static_cast<DecayPtr<Func>>( data );
1054 1055 1056
                (*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 : "" );
            });
1057 1058
        }

1059 1060 1061 1062 1063 1064 1065
        /**
         * \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
         */
1066
        template <typename Func>
1067
        RegisteredEvent onMediaInstanceStatusOpening( Func&& f )
1068
        {
1069 1070
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStatusOpening, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
1071
            {
1072
                auto callback = static_cast<DecayPtr<Func>>( data );
1073 1074 1075
                (*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 : "" );
            });
1076 1077
        }

1078 1079 1080 1081 1082 1083 1084
        /**
         * \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
         */
1085
        template <typename Func>
1086
        RegisteredEvent onMediaInstanceStatusPlaying( Func&& f )
1087
        {
1088 1089
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStatusPlaying, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
1090
            {
1091
                auto callback = static_cast<DecayPtr<Func>>( data );
1092 1093 1094
                (*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 : "" );
            });
1095 1096
        }

1097 1098 1099 1100 1101 1102 1103
        /**
         * \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
         */
1104
        template <typename Func>
1105
        RegisteredEvent onMediaInstanceStatusPause( Func&& f )
1106
        {
1107 1108
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStatusPause, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
1109
            {
1110
                auto callback = static_cast<DecayPtr<Func>>( data );
1111 1112 1113
                (*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 : "" );
            });
1114
        }
1115

1116 1117 1118 1119 1120 1121 1122
        /**
         * \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
         */
1123
        template <typename Func>
1124
        RegisteredEvent onMediaInstanceStatusEnd( Func&& f )
1125
        {
1126 1127
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStatusEnd, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
1128
            {
1129
                auto callback = static_cast<DecayPtr<Func>>( data );
1130 1131 1132
                (*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 : "" );
            });
1133
        }
1134

1135 1136 1137 1138 1139 1140 1141
        /**
         * \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
         */
1142
        template <typename Func>
Hugo Beauzée-Luyssen's avatar