EventManager.hpp 42.6 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](typename 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 247 248 249 250 251 252 253
    private:
        // Hold on to the object firing events. Otherwise, when copying/move
        // assigning over its object, the Internal parent class would be copied/moved
        // first, and only then would the event manager be copied/moved.
        // This can cause the last instance of the object to be released, and
        // then used by the event manager as it unregisters its callbacks.
        Media m_media;

254
    public:
255 256 257 258 259 260 261 262 263 264
        MediaEventManager(InternalPtr ptr, Media m)
            : EventManager( ptr )
            , m_media( std::move( m ) )
        {
        }
        ~MediaEventManager()
        {
            // Clear the events as long as the underlying VLC object is alive
            m_lambdas.clear();
        }
265

266
        /**
267 268
         * @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)
269 270
         */
        template <typename Func>
271
        RegisteredEvent onMetaChanged( Func&& f)
272
        {
273 274
            EXPECT_SIGNATURE(void(libvlc_meta_t));
            return handle( libvlc_MediaMetaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
275
            {
276
                auto callback = static_cast<DecayPtr<Func>>(data);
277 278 279
                (*callback)( e->u.media_meta_changed.meta_type );
            });
        }
280

281
        /**
282 283
         * @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)
284 285
         */
        template <typename Func>
286
        RegisteredEvent onSubItemAdded( Func&& f )
287
        {
288 289
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaSubItemAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
290
            {
291
                auto callback = static_cast<DecayPtr<Func>>(data);
292 293
                auto media = e->u.media_subitem_added.new_child;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
294 295 296
            });
        }

297 298 299 300
        /**
         * \brief onDurationChanged Registers an event called when a media duration changes
         * \param f A std::function<void(int64_t)> (or an equivalent Callable type)
         */
301
        template <typename Func>
302
        RegisteredEvent onDurationChanged( Func&& f )
303
        {
304 305
            EXPECT_SIGNATURE(void(int64_t));
            return handle(libvlc_MediaDurationChanged, 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_duration_changed.new_duration );
            });
        }

312 313 314 315 316
        /**
         * \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.
         */
317
        template <typename Func>
318
        RegisteredEvent onParsedChanged( Func&& f )
319
        {
320
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
321 322
            EXPECT_SIGNATURE( void(Media::ParsedStatus) );
            return handle(libvlc_MediaParsedChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
323
            {
324
                auto callback = static_cast<DecayPtr<Func>>(data);
325
                (*callback)( static_cast<Media::ParsedStatus>( e->u.media_parsed_changed.new_status ) );
326
            });
327 328 329 330 331 332 333 334
#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
335 336
        }

337 338 339 340 341 342 343 344
        /**
         * \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.
         *
         */
345
        template <typename Func>
346
        RegisteredEvent onFreed( Func&& f)
347
        {
348
            //FIXME: Provide a read-only Media wrapper, to avoid wild dangling references to appear.
349 350
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaFreed, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
351
            {
352
                auto callback = static_cast<DecayPtr<Func>>(data);
353 354
                auto media = e->u.media_freed.md;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
355 356 357
            });
        }

358 359 360 361
        /**
         * \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)
         */
362
        template <typename Func>
363
        RegisteredEvent onStateChanged( Func&& f)
364
        {
365
            //FIXME: Wrap libvlc_state_t in a class enum
366 367
            EXPECT_SIGNATURE(void(libvlc_state_t));
            return handle(libvlc_MediaStateChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
368
            {
369
                auto callback = static_cast<DecayPtr<Func>>(data);
370 371 372 373
                (*callback)( e->u.media_state_changed.new_state );
            });
        }

374 375 376 377 378 379
        /**
         * \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
         */
380
        template <typename Func>
381
        RegisteredEvent onSubItemTreeAdded( Func&& f)
382
        {
383
            EXPECT_SIGNATURE(void(MediaPtr));
384
            return handle(libvlc_MediaSubItemTreeAdded, 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_subitemtree_added.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
389 390
            });
        }
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418

#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(4, 0, 0, 0)
        /**
         * \brief onThumbnailGenerated is invoked upon success & failure of a thumbnail generation
         * \param A std::function<void(const Picture*)> (or an equivalent Callable type)
         *        The provided picture will be null if the thumbnail generation failed.
         *        In case of success, the thumbnail is only valid for the duration
         *        of the callback, but can be safely copied if needed.
         */
        template <typename Func>
        RegisteredEvent onThumbnailGenerated( Func&& f)
        {
            EXPECT_SIGNATURE(void(const Picture*));
            return handle(libvlc_MediaThumbnailGenerated, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
            {
                auto callback = static_cast<DecayPtr<Func>>(data);
                auto pic = e->u.media_thumbnail_generated.p_thumbnail;
                if ( pic != nullptr )
                {
                    Picture p{ pic };
                    (*callback)( &p );
                }
                else
                    (*callback)( nullptr );
            });
        }
#endif

419 420
};

421 422 423
/**
 * @brief The MediaPlayerEventManager class allows one to register MediaPlayer related events
 */
424
class MediaPlayerEventManager : public EventManager
425
{
426 427
    private:
        MediaPlayer m_mp;
428
    public:
429 430 431 432 433 434 435 436 437
        MediaPlayerEventManager(InternalPtr ptr, MediaPlayer mp)
            : EventManager( ptr )
            , m_mp( std::move( mp ) )
        {
        }
        ~MediaPlayerEventManager()
        {
            m_lambdas.clear();
        }
438

439 440 441 442
        /**
         * \brief onMediaChanged Registers an event called when the played media changes
         * \param f A std::function<void(MediaPtr)> (or an equivalent Callable type)
         */
443
        template <typename Func>
444
        RegisteredEvent onMediaChanged( Func&& f )
445
        {
446 447
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaPlayerMediaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
448
            {
449
                auto callback = static_cast<DecayPtr<Func>>( data );
450 451
                auto media = e->u.media_player_media_changed.new_media;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
452 453
            });
        }
454 455

        template <typename Func>
456
        RegisteredEvent onNothingSpecial( Func&& f )
457
        {
458
            return handle(libvlc_MediaPlayerNothingSpecial, std::forward<Func>( f ));
459 460
        }

461 462 463 464
        /**
         * \brief onOpening Registers an event called when the MediaPlayer starts initializing
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
465
        template <typename Func>
466
        RegisteredEvent onOpening( Func&& f )
467
        {
468
            return handle(libvlc_MediaPlayerOpening, std::forward<Func>( f ) );
469 470
        }

471 472 473 474 475
        /**
         * \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
         */
476
        template <typename Func>
477
        RegisteredEvent onBuffering( Func&& f )
478
        {
479 480 481 482 483 484
            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 );
            });
485 486
        }

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

497 498 499 500
        /**
         * \brief onPaused Registers an event called when the media player gets paused
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
501
        template <typename Func>
502
        RegisteredEvent onPaused(Func&& f)
503
        {
504
            return handle( libvlc_MediaPlayerPaused, std::forward<Func>( f ) );
505 506
        }

507 508 509 510
        /**
         * \brief onStopped Registers an event called when the media player gets stopped
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
511
        template <typename Func>
512
        RegisteredEvent onStopped(Func&& f)
513
        {
514
            return handle( libvlc_MediaPlayerStopped, std::forward<Func>( f ) );
515 516
        }

517
        // This never gets invoked
518
        template <typename Func>
519
        RegisteredEvent onForward(Func&& f)
520
        {
521
            return handle( libvlc_MediaPlayerForward, std::forward<Func>( f ) );
522 523
        }

524
        // This never gets invoked.
525
        template <typename Func>
526
        RegisteredEvent onBackward(Func&& f)
527
        {
528
            return handle( libvlc_MediaPlayerBackward, std::forward<Func>( f ) );
529 530
        }

531 532 533 534
        /**
         * \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)
         */
535
        template <typename Func>
536
        RegisteredEvent onEndReached(Func&& f)
537
        {
538
            return handle( libvlc_MediaPlayerEndReached, std::forward<Func>( f ) );
539 540
        }

541 542 543 544
        /**
         * \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)
         */
545
        template <typename Func>
546
        RegisteredEvent onEncounteredError(Func&& f)
547
        {
548
            return handle( libvlc_MediaPlayerEncounteredError, std::forward<Func>( f ) );
549 550
        }

551 552 553 554 555
        /**
         * \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.
         */
556
        template <typename Func>
557
        RegisteredEvent onTimeChanged( Func&& f )
558
        {
559 560
            EXPECT_SIGNATURE(void(libvlc_time_t));
            return handle( libvlc_MediaPlayerTimeChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
561
            {
562
                auto callback = static_cast<DecayPtr<Func>>( data );
563 564 565 566
                (*callback)( e->u.media_player_time_changed.new_time );
            });
        }

567 568 569 570 571
        /**
         * \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)
         */
572
        template <typename Func>
573
        RegisteredEvent onPositionChanged( Func&& f )
574
        {
575 576
            EXPECT_SIGNATURE(void(float));
            return handle( libvlc_MediaPlayerPositionChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
577
            {
578
                auto callback = static_cast<DecayPtr<Func>>( data );
579 580 581 582
                (*callback)( e->u.media_player_position_changed.new_position );
            });
        }

583 584 585 586 587
        /**
         * \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.
         */
588
        template <typename Func>
589
        RegisteredEvent onSeekableChanged( Func&& f )
590
        {
591 592
            EXPECT_SIGNATURE(void(bool));
            return handle( libvlc_MediaPlayerSeekableChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
593
            {
594
                auto callback = static_cast<DecayPtr<Func>>( data );
595
                (*callback)( e->u.media_player_seekable_changed.new_seekable != 0 );
596 597 598
            });
        }

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

615 616 617 618 619 620 621
        /**
         * \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)
         */
622
        template <typename Func>
623
        RegisteredEvent onTitleChanged( Func&& f )
624
        {
625 626
            EXPECT_SIGNATURE(void(int));
            return handle( libvlc_MediaPlayerTitleChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
627
            {
628
                auto callback = static_cast<DecayPtr<Func>>( data );
629 630 631 632
                (*callback)( e->u.media_player_title_changed.new_title );
            });
        }

633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
#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

653 654 655 656 657
        /**
         * \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
         */
658
        template <typename Func>
659
        RegisteredEvent onSnapshotTaken( Func&& f )
660
        {
661 662
            EXPECT_SIGNATURE(void(std::string));
            return handle( libvlc_MediaPlayerSnapshotTaken, 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_snapshot_taken.psz_filename );
            });
        }

669 670 671 672
        /**
         * \brief onLengthChanged Registers an event called when the length gets updated.
         * \param f A std::function<void(int64_t)> (or an equivalent Callable type)
         */
673
        template <typename Func>
674
        RegisteredEvent onLengthChanged( Func&& f )
675
        {
676 677
            EXPECT_SIGNATURE(void(libvlc_time_t));
            return handle( libvlc_MediaPlayerLengthChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
678
            {
679
                auto callback = static_cast<DecayPtr<Func>>( data );
680 681 682 683
                (*callback)( e->u.media_player_length_changed.new_length );
            });
        }

684 685 686 687 688
        /**
         * \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.
         */
689
        template <typename Func>
690
        RegisteredEvent onVout( Func&& f )
691
        {
692 693
            EXPECT_SIGNATURE(void(int));
            return handle( libvlc_MediaPlayerVout, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
694
            {
695
                auto callback = static_cast<DecayPtr<Func>>( data );
696 697 698 699
                (*callback)( e->u.media_player_vout.new_count );
            });
        }

700 701 702 703 704
        /**
         * \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.
         */
705
        template <typename Func>
706
        RegisteredEvent onScrambledChanged( Func&& f )
707
        {
708
            EXPECT_SIGNATURE(void(bool));
709
            return handle( libvlc_MediaPlayerScrambledChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
710
            {
711
                auto callback = static_cast<DecayPtr<Func>>( data );
712
                (*callback)( e->u.media_player_scrambled_changed.new_scrambled != 0 );
713 714 715
            });
        }

716
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
717 718 719 720 721 722
        /**
         * \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
         */
723
        template <typename Func>
724
        RegisteredEvent onESAdded( Func&& f )
725
        {
726
            //FIXME: Expose libvlc_track_type_t as an enum class
727 728
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
729
            {
730
                auto callback = static_cast<DecayPtr<Func>>( data );
731 732 733 734
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }

735 736 737 738 739 740
        /**
         * \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
         */
741
        template <typename Func>
742
        RegisteredEvent onESDeleted( Func&& f )
743
        {
744 745
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESDeleted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
746
            {
747
                auto callback = static_cast<DecayPtr<Func>>( data );
748 749 750 751
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }

752 753 754 755 756 757
        /**
         * \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
         */
758
        template <typename Func>
759
        RegisteredEvent onESSelected( Func&& f )
760
        {
761 762
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESSelected, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
763
            {
764
                auto callback = static_cast<DecayPtr<Func>>( data );
765 766 767
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }
768 769 770 771

        /**
         * \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)
772
         *          The provided string is the new current audio device.
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
         */
        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 );
            });
        }
842
#endif
843 844
};

845 846 847
/**
 * @brief The MediaListEventManager class allows one to register MediaList related events
 */
848
class MediaListEventManager : public EventManager
849
{
850 851
    private:
        MediaList m_ml;
852
    public:
853 854 855 856 857 858 859 860 861
        MediaListEventManager(InternalPtr ptr, MediaList ml)
            : EventManager( ptr )
            , m_ml( std::move( ml ) )
        {
        }
        ~MediaListEventManager()
        {
            m_lambdas.clear();
        }
862

863 864 865 866 867 868
        /**
         * \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
         */
869
        template <typename Func>
870
        RegisteredEvent onItemAdded( Func&& f )
871
        {
872 873
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListItemAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
874
            {
875
                auto callback = static_cast<DecayPtr<Func>>( data );
876 877 878
                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 );
879 880 881
            });
        }

882 883 884 885 886 887
        /**
         * \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
         */
888
        template <typename Func>
889
        RegisteredEvent onWillAddItem( Func&& f )
890
        {
891 892
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle( libvlc_MediaListWillAddItem, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
893
            {
894
                auto callback = static_cast<DecayPtr<Func>>( data );
895
                auto media = e->u.media_list_will_add_item.item;
896
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr,
897
                            e->u.media_list_will_add_item.index );
898 899 900
            });
        }

901 902 903 904 905 906
        /**
         * \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
         */
907
        template <typename Func>
908
        RegisteredEvent onItemDeleted( Func&& f )
909
        {
910 911
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListItemDeleted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
912
            {
913
                auto callback = static_cast<DecayPtr<Func>>( data );
914 915 916
                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 );
917 918 919
            });
        }

920 921 922 923 924 925
        /**
         * \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
         */
926
        template <typename Func>
927
        RegisteredEvent onWillDeleteItem( Func&& f )
928
        {
929 930
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListWillDeleteItem, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
931
            {
932
                auto callback = static_cast<DecayPtr<Func>>( data );
933 934 935
                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 );
936 937
            });
        }
938

939
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
940 941 942 943 944
        template <typename Func>
        RegisteredEvent onEndReached( Func&& f )
        {
            return handle( libvlc_MediaListEndReached, std::forward<Func>( f ) );
        }
945
#endif
946 947
};

948 949 950 951
/**
 * @brief The MediaListPlayerEventManager class
 * Those events aren't sent by VLC so far.
 */
952
class MediaListPlayerEventManager : public EventManager
953
{
954 955
    private:
        MediaListPlayer m_mlp;
956
    public:
957 958 959 960 961 962 963 964 965
        MediaListPlayerEventManager(InternalPtr ptr, MediaListPlayer mlp)
            : EventManager( ptr )
            , m_mlp( std::move( mlp ) )
        {
        }
        ~MediaListPlayerEventManager()
        {
            m_lambdas.clear();
        }
966

967
        template <typename Func>
968
        RegisteredEvent onPlayed(Func&& f)
969
        {
970
            return handle(libvlc_MediaListPlayerPlayed, std::forward<Func>( f ) );
971 972
        }

973
        template <typename Func>
974
        RegisteredEvent onNextItemSet( Func&& f )
975
        {
976 977
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaListPlayerNextItemSet, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
978
            {
979
                auto callback = static_cast<DecayPtr<Func>>( data );
980 981
                auto media = e->u.media_list_player_next_item_set.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
982
            });
983 984
        }

985
        template <typename Func>
986
        RegisteredEvent onStopped( Func&& f )
987
        {
988
            return handle(libvlc_MediaListPlayerStopped, std::forward<Func>( f ) );
989
        }
990
};
991

992
#if LIBVLC_VERSION_INT < LIBVLC_VERSION(3, 0, 0, 0)
993 994 995
/**
 * @brief The MediaDiscovererEventManager class allows one to register MediaDiscoverer related events
 */
996 997 998 999 1000
class MediaDiscovererEventManager : public EventManager
{
    public:
        MediaDiscovererEventManager(InternalPtr ptr) : EventManager( ptr ) {}

1001 1002 1003 1004
        /**
         * \brief onStarted Registers an event called when the discovery starts
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
1005
        template <typename Func>
1006
        RegisteredEvent onStarted(Func&& f)
1007
        {
1008
            return handle(libvlc_MediaDiscovererStarted, std::forward<Func>( f ) );
1009 1010
        }

1011 1012 1013 1014
        /**
         * \brief onStopped Registers an event called when the discovery stops
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
1015
        template <typename Func>
1016
        RegisteredEvent onStopped(Func&& f)
1017
        {
1018
            return handle(libvlc_MediaDiscovererEnded, std::forward<Func>( f ) );
1019
        }
1020
};
1021
#endif
1022

1023 1024 1025 1026 1027 1028 1029 1030
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)

/*
* \brief The RendererDiscovererEventManager class allows one to register
* renderer discoverer related events
*/
class RendererDiscovererEventManager : public EventManager
{
1031 1032
private:
    RendererDiscoverer m_rd;
1033
public:
1034 1035 1036 1037 1038 1039 1040 1041 1042
    RendererDiscovererEventManager( InternalPtr ptr, RendererDiscoverer rd )
        : EventManager(ptr)
        , m_rd( std::move( rd ) )
    {
    }
    ~RendererDiscovererEventManager()
    {
        m_lambdas.clear();
    }
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071

    template <typename Func>
    RegisteredEvent onItemAdded( Func&& f )
    {
        EXPECT_SIGNATURE(void(const RendererDiscoverer::Item&));
        return handle(libvlc_RendererDiscovererItemAdded, std::forward<Func>( f ),
                      [](const libvlc_event_t* e, void* data)
        {
            auto callback = static_cast<DecayPtr<Func>>( data );
            (*callback)( RendererDiscoverer::Item( e->u.renderer_discoverer_item_added.item ) );
        });
    }

    template <typename Func>
    RegisteredEvent onItemDeleted( Func&& f )
    {
        EXPECT_SIGNATURE(void(const RendererDiscoverer::Item&));
        return handle(libvlc_RendererDiscovererItemDeleted, std::forward<Func>( f ),
                      [](const libvlc_event_t* e, void* data)
        {
            auto callback = static_cast<DecayPtr<Func>>( data );
            (*callback)( RendererDiscoverer::Item( e->u.renderer_discoverer_item_deleted.item ) );
        });
    }

};

#endif

1072 1073 1074
}

#endif // LIBVLC_EVENTMANAGER_HPP