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

#ifndef LIBVLC_EVENTMANAGER_HPP
#define LIBVLC_EVENTMANAGER_HPP

#include <string>
27

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

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

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

38 39 40
namespace VLC
{

41 42 43
/**
 * @brief This class serves as a base for all event managers.
 *
44 45 46
 * 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
47 48
 */
class EventManager : public Internal<libvlc_event_manager_t>
49
{
50 51 52 53
protected:
    template <typename T>
    using DecayPtr = typename std::add_pointer<typename std::decay<T>::type>::type;

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

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

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

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

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

    private:
106
        // Deduced type is Func& in case of lvalue; Func in case of rvalue.
107 108 109
        // 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;
110 111 112 113 114 115
        // EventManager always outlive EventHandler, no need for smart pointer
        EventManager* m_eventManager;
        Wrapper m_wrapper;
        libvlc_event_e m_eventType;
    };

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

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

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

        unregister(args...);
135 136
    }

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

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

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

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

195
    using RegisteredEvent = EventHandlerBase*;
196

197 198
protected:

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

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

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

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

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

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

294 295 296 297 298
        /**
         * \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.
         */
299
        template <typename Func>
300
        RegisteredEvent onParsedChanged( Func&& f )
301
        {
302 303
            EXPECT_SIGNATURE(void(bool));
            return handle( libvlc_MediaParsedChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
304
            {
305
                auto callback = static_cast<DecayPtr<Func>>(data);
306 307 308 309
                (*callback)( e->u.media_parsed_changed.new_status );
            });
        }

310 311 312 313 314 315 316 317
        /**
         * \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.
         *
         */
318
        template <typename Func>
319
        RegisteredEvent onFreed( Func&& f)
320
        {
321
            //FIXME: Provide a read-only Media wrapper, to avoid wild dangling references to appear.
322 323
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaFreed, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
324
            {
325
                auto callback = static_cast<DecayPtr<Func>>(data);
326 327
                auto media = e->u.media_freed.md;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
328 329 330
            });
        }

331 332 333 334
        /**
         * \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)
         */
335
        template <typename Func>
336
        RegisteredEvent onStateChanged( Func&& f)
337
        {
338
            //FIXME: Wrap libvlc_state_t in a class enum
339 340
            EXPECT_SIGNATURE(void(libvlc_state_t));
            return handle(libvlc_MediaStateChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
341
            {
342
                auto callback = static_cast<DecayPtr<Func>>(data);
343 344 345 346
                (*callback)( e->u.media_state_changed.new_state );
            });
        }

347 348 349 350 351 352
        /**
         * \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
         */
353
        template <typename Func>
354
        RegisteredEvent onSubItemTreeAdded( Func&& f)
355
        {
356
            EXPECT_SIGNATURE(void(MediaPtr));
357
            return handle(libvlc_MediaSubItemTreeAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
358
            {
359
                auto callback = static_cast<DecayPtr<Func>>(data);
360 361
                auto media = e->u.media_subitemtree_added.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
362 363
            });
        }
364 365
};

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

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

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

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

406 407 408 409 410
        /**
         * \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
         */
411
        template <typename Func>
412
        RegisteredEvent onBuffering( Func&& f )
413
        {
414 415 416 417 418 419
            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 );
            });
420 421
        }

422 423 424 425
        /**
         * \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)
         */
426
        template <typename Func>
427
        RegisteredEvent onPlaying( Func&& f )
428
        {
429
            return handle( libvlc_MediaPlayerPlaying, std::forward<Func>( f ) );
430 431
        }

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

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

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

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

466 467 468 469
        /**
         * \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)
         */
470
        template <typename Func>
471
        RegisteredEvent onEndReached(Func&& f)
472
        {
473
            return handle( libvlc_MediaPlayerEndReached, std::forward<Func>( f ) );
474 475
        }

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

486 487 488 489 490
        /**
         * \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.
         */
491
        template <typename Func>
492
        RegisteredEvent onTimeChanged( Func&& f )
493
        {
494 495
            EXPECT_SIGNATURE(void(libvlc_time_t));
            return handle( libvlc_MediaPlayerTimeChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
496
            {
497
                auto callback = static_cast<DecayPtr<Func>>( data );
498 499 500 501
                (*callback)( e->u.media_player_time_changed.new_time );
            });
        }

502 503 504 505 506
        /**
         * \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)
         */
507
        template <typename Func>
508
        RegisteredEvent onPositionChanged( Func&& f )
509
        {
510 511
            EXPECT_SIGNATURE(void(float));
            return handle( libvlc_MediaPlayerPositionChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
512
            {
513
                auto callback = static_cast<DecayPtr<Func>>( data );
514 515 516 517
                (*callback)( e->u.media_player_position_changed.new_position );
            });
        }

518 519 520 521 522
        /**
         * \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.
         */
523
        template <typename Func>
524
        RegisteredEvent onSeekableChanged( Func&& f )
525
        {
526 527
            EXPECT_SIGNATURE(void(bool));
            return handle( libvlc_MediaPlayerSeekableChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
528
            {
529
                auto callback = static_cast<DecayPtr<Func>>( data );
530
                (*callback)( e->u.media_player_seekable_changed.new_seekable != 0 );
531 532 533
            });
        }

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

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

568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
#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

588 589 590 591 592
        /**
         * \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
         */
593
        template <typename Func>
594
        RegisteredEvent onSnapshotTaken( Func&& f )
595
        {
596 597
            EXPECT_SIGNATURE(void(std::string));
            return handle( libvlc_MediaPlayerSnapshotTaken, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
598
            {
599
                auto callback = static_cast<DecayPtr<Func>>( data );
600 601 602 603
                (*callback)( e->u.media_player_snapshot_taken.psz_filename );
            });
        }

604 605 606 607
        /**
         * \brief onLengthChanged Registers an event called when the length gets updated.
         * \param f A std::function<void(int64_t)> (or an equivalent Callable type)
         */
608
        template <typename Func>
609
        RegisteredEvent onLengthChanged( Func&& f )
610
        {
611 612
            EXPECT_SIGNATURE(void(libvlc_time_t));
            return handle( libvlc_MediaPlayerLengthChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
613
            {
614
                auto callback = static_cast<DecayPtr<Func>>( data );
615 616 617 618
                (*callback)( e->u.media_player_length_changed.new_length );
            });
        }

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

635 636 637 638 639
        /**
         * \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.
         */
640
        template <typename Func>
641
        RegisteredEvent onScrambledChanged( Func&& f )
642
        {
643
            EXPECT_SIGNATURE(void(bool));
644
            return handle( libvlc_MediaPlayerScrambledChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
645
            {
646
                auto callback = static_cast<DecayPtr<Func>>( data );
647
                (*callback)( e->u.media_player_scrambled_changed.new_scrambled != 0 );
648 649 650
            });
        }

651
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
652 653 654 655 656 657
        /**
         * \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
         */
658
        template <typename Func>
659
        RegisteredEvent onESAdded( Func&& f )
660
        {
661
            //FIXME: Expose libvlc_track_type_t as an enum class
662 663
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
664
            {
665
                auto callback = static_cast<DecayPtr<Func>>( data );
666 667 668 669
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }

670 671 672 673 674 675
        /**
         * \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
         */
676
        template <typename Func>
677
        RegisteredEvent onESDeleted( Func&& f )
678
        {
679 680
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESDeleted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
681
            {
682
                auto callback = static_cast<DecayPtr<Func>>( data );
683 684 685 686
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }

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

        /**
         * \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)
         *          The provided string is the new current volume.
         */
        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 );
            });
        }
777
#endif
778 779
};

780 781 782
/**
 * @brief The MediaListEventManager class allows one to register MediaList related events
 */
783
class MediaListEventManager : public EventManager
784 785
{
    public:
786 787
        MediaListEventManager(InternalPtr ptr) : EventManager( ptr ) {}

788 789 790 791 792 793
        /**
         * \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
         */
794
        template <typename Func>
795
        RegisteredEvent onItemAdded( Func&& f )
796
        {
797 798
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListItemAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
799
            {
800
                auto callback = static_cast<DecayPtr<Func>>( data );
801 802 803
                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 );
804 805 806
            });
        }

807 808 809 810 811 812
        /**
         * \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
         */
813
        template <typename Func>
814
        RegisteredEvent onWillAddItem( Func&& f )
815
        {
816 817
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle( libvlc_MediaListWillAddItem, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
818
            {
819
                auto callback = static_cast<DecayPtr<Func>>( data );
820
                auto media = e->u.media_list_will_add_item.item;
821
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr,
822
                            e->u.media_list_will_add_item.index );
823 824 825
            });
        }

826 827 828 829 830 831
        /**
         * \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
         */
832
        template <typename Func>
833
        RegisteredEvent onItemDeleted( Func&& f )
834
        {
835 836
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListItemDeleted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
837
            {
838
                auto callback = static_cast<DecayPtr<Func>>( data );
839 840 841
                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 );
842 843 844
            });
        }

845 846 847 848 849 850
        /**
         * \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
         */
851
        template <typename Func>
852
        RegisteredEvent onWillDeleteItem( Func&& f )
853
        {
854 855
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListWillDeleteItem, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
856
            {
857
                auto callback = static_cast<DecayPtr<Func>>( data );
858 859 860
                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 );
861 862
            });
        }
863 864
};

865 866 867 868
/**
 * @brief The MediaListPlayerEventManager class
 * Those events aren't sent by VLC so far.
 */
869
class MediaListPlayerEventManager : public EventManager
870 871
{
    public:
872 873
        MediaListPlayerEventManager(InternalPtr ptr) : EventManager( ptr ) {}

874
        template <typename Func>
875
        RegisteredEvent onPlayed(Func&& f)
876
        {
877
            return handle(libvlc_MediaListPlayerPlayed, std::forward<Func>( f ) );
878 879
        }

880
        template <typename Func>
881
        RegisteredEvent onNextItemSet( Func&& f )
882
        {
883 884
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaListPlayerNextItemSet, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
885
            {
886
                auto callback = static_cast<DecayPtr<Func>>( data );
887 888
                auto media = e->u.media_list_player_next_item_set.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
889
            });
890 891
        }

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

899 900 901
/**
 * @brief The MediaDiscovererEventManager class allows one to register MediaDiscoverer related events
 */
902 903 904 905 906
class MediaDiscovererEventManager : public EventManager
{
    public:
        MediaDiscovererEventManager(InternalPtr ptr) : EventManager( ptr ) {}

907 908 909 910
        /**
         * \brief onStarted Registers an event called when the discovery starts
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
911
        template <typename Func>
912
        RegisteredEvent onStarted(Func&& f)
913
        {
914
            return handle(libvlc_MediaDiscovererStarted, std::forward<Func>( f ) );
915 916
        }

917 918 919 920
        /**
         * \brief onStopped Registers an event called when the discovery stops
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
921
        template <typename Func>
922
        RegisteredEvent onStopped(Func&& f)
923
        {
924
            return handle(libvlc_MediaDiscovererEnded, std::forward<Func>( f ) );
925
        }
926
};
927

928 929 930
/**
 * @brief The VLMEventManager class allows one to register VLM related events
 */
931 932 933
class VLMEventManager : public EventManager
{
    public:
934
        VLMEventManager(InternalPtr ptr) : EventManager(ptr) {}
935

936 937 938 939 940
        /**
         * \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
         */
941
        template <typename Func>
942
        RegisteredEvent onMediaAdded( Func&& f )
943
        {
944 945
            EXPECT_SIGNATURE(void(std::string));
            return handle(libvlc_VlmMediaAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
946
            {
947
                auto callback = static_cast<DecayPtr<Func>>( data );
948 949
                (*callback)( e->u.vlm_media_event.psz_media_name ? e->u.vlm_media_event.psz_media_name : "" );
            });
950 951
        }

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

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

984 985 986 987 988 989 990
        /**
         * \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
         */
991
        template <typename Func>
992
        RegisteredEvent onMediaInstanceStarted( Func&& f )
993
        {
994 995
            EXPECT_SIGNATURE(void(std::string, std::string));
            return handle(libvlc_VlmMediaInstanceStarted, 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 : "",
                             e->u.vlm_media_event.psz_instance_name ? e->u.vlm_media_event.psz_instance_name : "" );
            });
1001 1002
        }

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

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

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

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

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

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

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

#endif // LIBVLC_EVENTMANAGER_HPP