EventManager.hpp 41.2 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
{
    public:
247
        MediaEventManager(InternalPtr ptr) : EventManager( ptr ) {}
248

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

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

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

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

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

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

357 358 359 360 361 362
        /**
         * \brief onSubItemTreeAdded Registers an event called when all subitem have been added.
         * \param f A std::function<void(MediaPtr)> (or an equivalent Callable type)
         *          The provided Media is the media for which this event has been registered,
         *          not a potential child media
         */
363
        template <typename Func>
364
        RegisteredEvent onSubItemTreeAdded( Func&& f)
365
        {
366
            EXPECT_SIGNATURE(void(MediaPtr));
367
            return handle(libvlc_MediaSubItemTreeAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
368
            {
369
                auto callback = static_cast<DecayPtr<Func>>(data);
370 371
                auto media = e->u.media_subitemtree_added.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
372 373
            });
        }
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401

#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

402 403
};

404 405 406
/**
 * @brief The MediaPlayerEventManager class allows one to register MediaPlayer related events
 */
407
class MediaPlayerEventManager : public EventManager
408 409
{
    public:
410 411
        MediaPlayerEventManager(InternalPtr ptr) : EventManager( ptr ) {}

412 413 414 415
        /**
         * \brief onMediaChanged Registers an event called when the played media changes
         * \param f A std::function<void(MediaPtr)> (or an equivalent Callable type)
         */
416
        template <typename Func>
417
        RegisteredEvent onMediaChanged( Func&& f )
418
        {
419 420
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaPlayerMediaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
421
            {
422
                auto callback = static_cast<DecayPtr<Func>>( data );
423 424
                auto media = e->u.media_player_media_changed.new_media;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
425 426
            });
        }
427 428

        template <typename Func>
429
        RegisteredEvent onNothingSpecial( Func&& f )
430
        {
431
            return handle(libvlc_MediaPlayerNothingSpecial, std::forward<Func>( f ));
432 433
        }

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

444 445 446 447 448
        /**
         * \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
         */
449
        template <typename Func>
450
        RegisteredEvent onBuffering( Func&& f )
451
        {
452 453 454 455 456 457
            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 );
            });
458 459
        }

460 461 462 463
        /**
         * \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)
         */
464
        template <typename Func>
465
        RegisteredEvent onPlaying( Func&& f )
466
        {
467
            return handle( libvlc_MediaPlayerPlaying, std::forward<Func>( f ) );
468 469
        }

470 471 472 473
        /**
         * \brief onPaused Registers an event called when the media player gets paused
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
474
        template <typename Func>
475
        RegisteredEvent onPaused(Func&& f)
476
        {
477
            return handle( libvlc_MediaPlayerPaused, std::forward<Func>( f ) );
478 479
        }

480 481 482 483
        /**
         * \brief onStopped Registers an event called when the media player gets stopped
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
484
        template <typename Func>
485
        RegisteredEvent onStopped(Func&& f)
486
        {
487
            return handle( libvlc_MediaPlayerStopped, std::forward<Func>( f ) );
488 489
        }

490
        // This never gets invoked
491
        template <typename Func>
492
        RegisteredEvent onForward(Func&& f)
493
        {
494
            return handle( libvlc_MediaPlayerForward, std::forward<Func>( f ) );
495 496
        }

497
        // This never gets invoked.
498
        template <typename Func>
499
        RegisteredEvent onBackward(Func&& f)
500
        {
501
            return handle( libvlc_MediaPlayerBackward, std::forward<Func>( f ) );
502 503
        }

504 505 506 507
        /**
         * \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)
         */
508
        template <typename Func>
509
        RegisteredEvent onEndReached(Func&& f)
510
        {
511
            return handle( libvlc_MediaPlayerEndReached, std::forward<Func>( f ) );
512 513
        }

514 515 516 517
        /**
         * \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)
         */
518
        template <typename Func>
519
        RegisteredEvent onEncounteredError(Func&& f)
520
        {
521
            return handle( libvlc_MediaPlayerEncounteredError, std::forward<Func>( f ) );
522 523
        }

524 525 526 527 528
        /**
         * \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.
         */
529
        template <typename Func>
530
        RegisteredEvent onTimeChanged( Func&& f )
531
        {
532 533
            EXPECT_SIGNATURE(void(libvlc_time_t));
            return handle( libvlc_MediaPlayerTimeChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
534
            {
535
                auto callback = static_cast<DecayPtr<Func>>( data );
536 537 538 539
                (*callback)( e->u.media_player_time_changed.new_time );
            });
        }

540 541 542 543 544
        /**
         * \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)
         */
545
        template <typename Func>
546
        RegisteredEvent onPositionChanged( Func&& f )
547
        {
548 549
            EXPECT_SIGNATURE(void(float));
            return handle( libvlc_MediaPlayerPositionChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
550
            {
551
                auto callback = static_cast<DecayPtr<Func>>( data );
552 553 554 555
                (*callback)( e->u.media_player_position_changed.new_position );
            });
        }

556 557 558 559 560
        /**
         * \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.
         */
561
        template <typename Func>
562
        RegisteredEvent onSeekableChanged( Func&& f )
563
        {
564 565
            EXPECT_SIGNATURE(void(bool));
            return handle( libvlc_MediaPlayerSeekableChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
566
            {
567
                auto callback = static_cast<DecayPtr<Func>>( data );
568
                (*callback)( e->u.media_player_seekable_changed.new_seekable != 0 );
569 570 571
            });
        }

572 573 574 575 576
        /**
         * \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.
         */
577
        template <typename Func>
578
        RegisteredEvent onPausableChanged( Func&& f )
579
        {
580 581
            EXPECT_SIGNATURE(void(bool));
            return handle( libvlc_MediaPlayerSeekableChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
582
            {
583
                auto callback = static_cast<DecayPtr<Func>>( data );
584
                (*callback)( e->u.media_player_seekable_changed.new_seekable != 0 );
585 586 587
            });
        }

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

606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
#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

626 627 628 629 630
        /**
         * \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
         */
631
        template <typename Func>
632
        RegisteredEvent onSnapshotTaken( Func&& f )
633
        {
634 635
            EXPECT_SIGNATURE(void(std::string));
            return handle( libvlc_MediaPlayerSnapshotTaken, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
636
            {
637
                auto callback = static_cast<DecayPtr<Func>>( data );
638 639 640 641
                (*callback)( e->u.media_player_snapshot_taken.psz_filename );
            });
        }

642 643 644 645
        /**
         * \brief onLengthChanged Registers an event called when the length gets updated.
         * \param f A std::function<void(int64_t)> (or an equivalent Callable type)
         */
646
        template <typename Func>
647
        RegisteredEvent onLengthChanged( Func&& f )
648
        {
649 650
            EXPECT_SIGNATURE(void(libvlc_time_t));
            return handle( libvlc_MediaPlayerLengthChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
651
            {
652
                auto callback = static_cast<DecayPtr<Func>>( data );
653 654 655 656
                (*callback)( e->u.media_player_length_changed.new_length );
            });
        }

657 658 659 660 661
        /**
         * \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.
         */
662
        template <typename Func>
663
        RegisteredEvent onVout( Func&& f )
664
        {
665 666
            EXPECT_SIGNATURE(void(int));
            return handle( libvlc_MediaPlayerVout, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
667
            {
668
                auto callback = static_cast<DecayPtr<Func>>( data );
669 670 671 672
                (*callback)( e->u.media_player_vout.new_count );
            });
        }

673 674 675 676 677
        /**
         * \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.
         */
678
        template <typename Func>
679
        RegisteredEvent onScrambledChanged( Func&& f )
680
        {
681
            EXPECT_SIGNATURE(void(bool));
682
            return handle( libvlc_MediaPlayerScrambledChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
683
            {
684
                auto callback = static_cast<DecayPtr<Func>>( data );
685
                (*callback)( e->u.media_player_scrambled_changed.new_scrambled != 0 );
686 687 688
            });
        }

689
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
690 691 692 693 694 695
        /**
         * \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
         */
696
        template <typename Func>
697
        RegisteredEvent onESAdded( Func&& f )
698
        {
699
            //FIXME: Expose libvlc_track_type_t as an enum class
700 701
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
702
            {
703
                auto callback = static_cast<DecayPtr<Func>>( data );
704 705 706 707
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }

708 709 710 711 712 713
        /**
         * \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
         */
714
        template <typename Func>
715
        RegisteredEvent onESDeleted( Func&& f )
716
        {
717 718
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESDeleted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
719
            {
720
                auto callback = static_cast<DecayPtr<Func>>( data );
721 722 723 724
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }

725 726 727 728 729 730
        /**
         * \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
         */
731
        template <typename Func>
732
        RegisteredEvent onESSelected( Func&& f )
733
        {
734 735
            EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
            return handle( libvlc_MediaPlayerESSelected, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
736
            {
737
                auto callback = static_cast<DecayPtr<Func>>( data );
738 739 740
                (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
            });
        }
741 742 743 744

        /**
         * \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)
745
         *          The provided string is the new current audio device.
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 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
         */
        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 );
            });
        }
815
#endif
816 817
};

818 819 820
/**
 * @brief The MediaListEventManager class allows one to register MediaList related events
 */
821
class MediaListEventManager : public EventManager
822 823
{
    public:
824 825
        MediaListEventManager(InternalPtr ptr) : EventManager( ptr ) {}

826 827 828 829 830 831
        /**
         * \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
         */
832
        template <typename Func>
833
        RegisteredEvent onItemAdded( Func&& f )
834
        {
835 836
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListItemAdded, 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_added.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr,
                             e->u.media_list_item_added.index );
842 843 844
            });
        }

845 846 847 848 849 850
        /**
         * \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
         */
851
        template <typename Func>
852
        RegisteredEvent onWillAddItem( Func&& f )
853
        {
854 855
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle( libvlc_MediaListWillAddItem, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
856
            {
857
                auto callback = static_cast<DecayPtr<Func>>( data );
858
                auto media = e->u.media_list_will_add_item.item;
859
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr,
860
                            e->u.media_list_will_add_item.index );
861 862 863
            });
        }

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

883 884 885 886 887 888
        /**
         * \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
         */
889
        template <typename Func>
890
        RegisteredEvent onWillDeleteItem( Func&& f )
891
        {
892 893
            EXPECT_SIGNATURE(void(MediaPtr, int));
            return handle(libvlc_MediaListWillDeleteItem, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
894
            {
895
                auto callback = static_cast<DecayPtr<Func>>( data );
896 897 898
                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 );
899 900
            });
        }
901

902
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(3, 0, 0, 0)
903 904 905 906 907
        template <typename Func>
        RegisteredEvent onEndReached( Func&& f )
        {
            return handle( libvlc_MediaListEndReached, std::forward<Func>( f ) );
        }
908
#endif
909 910
};

911 912 913 914
/**
 * @brief The MediaListPlayerEventManager class
 * Those events aren't sent by VLC so far.
 */
915
class MediaListPlayerEventManager : public EventManager
916 917
{
    public:
918 919
        MediaListPlayerEventManager(InternalPtr ptr) : EventManager( ptr ) {}

920
        template <typename Func>
921
        RegisteredEvent onPlayed(Func&& f)
922
        {
923
            return handle(libvlc_MediaListPlayerPlayed, std::forward<Func>( f ) );
924 925
        }

926
        template <typename Func>
927
        RegisteredEvent onNextItemSet( Func&& f )
928
        {
929 930
            EXPECT_SIGNATURE(void(MediaPtr));
            return handle(libvlc_MediaListPlayerNextItemSet, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
931
            {
932
                auto callback = static_cast<DecayPtr<Func>>( data );
933 934
                auto media = e->u.media_list_player_next_item_set.item;
                (*callback)( media != nullptr ? std::make_shared<Media>( media, true ) : nullptr );
935
            });
936 937
        }

938
        template <typename Func>
939
        RegisteredEvent onStopped( Func&& f )
940
        {
941
            return handle(libvlc_MediaListPlayerStopped, std::forward<Func>( f ) );
942
        }
943
};
944

945
#if LIBVLC_VERSION_INT < LIBVLC_VERSION(3, 0, 0, 0)
946 947 948
/**
 * @brief The MediaDiscovererEventManager class allows one to register MediaDiscoverer related events
 */
949 950 951 952 953
class MediaDiscovererEventManager : public EventManager
{
    public:
        MediaDiscovererEventManager(InternalPtr ptr) : EventManager( ptr ) {}

954 955 956 957
        /**
         * \brief onStarted Registers an event called when the discovery starts
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
958
        template <typename Func>
959
        RegisteredEvent onStarted(Func&& f)
960
        {
961
            return handle(libvlc_MediaDiscovererStarted, std::forward<Func>( f ) );
962 963
        }

964 965 966 967
        /**
         * \brief onStopped Registers an event called when the discovery stops
         * \param f A std::function<void(void)> (or an equivalent Callable type)
         */
968
        template <typename Func>
969
        RegisteredEvent onStopped(Func&& f)
970
        {
971
            return handle(libvlc_MediaDiscovererEnded, std::forward<Func>( f ) );
972
        }
973
};
974
#endif
975

976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
#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
{
public:
    RendererDiscovererEventManager( InternalPtr ptr ) : EventManager(ptr) {}

    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

1015 1016 1017
}

#endif // LIBVLC_EVENTMANAGER_HPP